Есть два предостережения к моему решению:
1) Вы сказали, что можете добавлять индексы, но не изменять схему, поэтому я не уверен, сработает ли это для вас или нет, поскольку вы не можете иметь индексы на основе функций в MySQL, и вам нужно будет создать дополнительный столбец в таблице B. 2) Другое предостережение относительно этого решения заключается в том, что вы должны использовать механизм MyISAM для таблицы B. Если вы не можете использовать MyISAM, это решение не будет работать, поскольку для пространственных индексов поддерживается только MyISAM.
Итак, предполагая, что два вышеперечисленных не являются проблемой для вас, следующее должно работать и обеспечивать хорошую производительность:
Это решение использует поддержку MySQL для пространственных данных (см. документацию здесь а>). Хотя типы пространственных данных могут быть добавлены к различным механизмам хранения, для индексов пространственного R-дерева поддерживается только MyISAM (см. здесь), которые необходимы для достижения необходимой производительности. Еще одно ограничение заключается в том, что типы пространственных данных работают только с числовыми данными, поэтому вы не можете использовать этот метод со строковыми запросами диапазона.
Я не буду вдаваться в подробности теории того, как работают пространственные типы и чем полезен пространственный индекс, но вы должны посмотреть объяснение Джереми Коула здесь относительно того, как использовать типы пространственных данных и индексы для GeoIP поиск. Также посмотрите комментарии, поскольку они поднимают некоторые полезные моменты и альтернативы, если вам нужна грубая производительность и вы можете отказаться от некоторой точности.
Основная предпосылка заключается в том, что мы можем взять начало/конец и использовать их две для создания четырех различных точек, по одной для каждого угла прямоугольника с центром вокруг 0,0 на сетке xy, а затем выполнить быстрый поиск в пространственной координате. index, чтобы определить, находится ли интересующий нас конкретный момент времени в пределах прямоугольника или нет. Как упоминалось ранее, см. объяснение Джереми Коула для более подробного обзора того, как это работает.
В вашем конкретном случае нам нужно будет сделать следующее:
1) Измените таблицу, чтобы она стала таблицей MyISAM (обратите внимание, что вы не должны этого делать, если вы полностью не осведомлены о последствиях такого изменения, таких как отсутствие транзакций и поведение блокировки таблицы, связанное с MyISAM).
alter table B engine = MyISAM;
2) Затем мы добавляем новый столбец, который будет содержать пространственные данные. Мы будем использовать тип данных polygon, так как нам нужно иметь возможность хранить полный прямоугольник.
alter table B add column time_poly polygon NOT NULL;
3) Затем мы заполняем новый столбец данными (имейте в виду, что любые процессы, которые обновляют или вставляют в таблицу B, должны быть изменены, чтобы убедиться, что они также заполняют новый столбец). Поскольку начальный и конечный диапазоны — это время, нам потребуется преобразовать их в числа с помощью функции unix_timestamp (см. здесь описание того, как это работает).
update B set time_poly := LINESTRINGFROMWKB(LINESTRING(
POINT(unix_timestamp(start_time), -1),
POINT(unix_timestamp(end_time), -1),
POINT(unix_timestamp(end_time), 1),
POINT(unix_timestamp(start_time), 1),
POINT(unix_timestamp(start_time), -1)
));
4) Затем мы добавляем в таблицу пространственный индекс (как упоминалось ранее, это будет работать только для таблицы MyISAM и приведет к ошибке «ОШИБКА 1464 (HY000): используемый тип таблицы не поддерживает пространственные индексы»).
alter table B add SPATIAL KEY `IXs_time_poly` (`time_poly`);
5) Затем вам нужно будет использовать следующий выбор, чтобы использовать пространственный индекс при запросе данных.
SELECT A.id, B.id
FROM A inner join B force index (IXs_time_poly)
ON MBRCONTAINS(B.time_poly, POINTFROMWKB(POINT(unix_timestamp(A.event_time), 0)));
Принудительный индекс нужен для того, чтобы на 100 % убедиться, что MySQL будет использовать индекс для поиска. Если все прошло хорошо, запуск объяснения для приведенного выше выбора должен показать что-то похожее на следующее:
mysql> explain SELECT A.id, B.id
-> FROM A inner join B force index (IXs_time_poly)
-> on MBRCONTAINS(B.time_poly, POINTFROMWKB(POINT(unix_timestamp(A.event_time), 0)));
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------------------------------------------+
| 1 | SIMPLE | A | ALL | NULL | NULL | NULL | NULL | 1065 | |
| 1 | SIMPLE | B | ALL | IXs_time_poly | NULL | NULL | NULL | 7969897 | Range checked for each record (index map: 0x10) |
+----+-------------+-------+------+---------------+------+---------+------+---------+-------------------------------------------------+
2 rows in set (0.00 sec)
Пожалуйста, обратитесь к анализу Джереми Коула для получения подробной информации о преимуществах производительности этого метода по сравнению с предложением between.
Дайте знать, если у вас появятся вопросы.
Спасибо,
-Дипин
person
Dipin
schedule
19.02.2009