В моем решении есть две оговорки:
1) Вы сказали, что можете добавлять индексы, но не изменять схему, поэтому я не уверен, сработает ли это для вас или нет, поскольку у вас не может быть индексов на основе функций в MySQL, и вам нужно будет создать дополнительный столбец в таблице B.
2) Другим предостережением для этого решения является то, что вы должны использовать механизм MyISAM для таблицы B. Если вы не можете использовать MyISAM, то это решение не будет работать, поскольку для пространственных индексов поддерживается только MyISAM.
Итак, если предположить, что вышеупомянутые два не являются проблемой для вас, следующее должно работать и дать вам хорошую производительность:
В этом решении используется поддержка MySQL для пространственных данных (см. документацию здесь ). Хотя пространственные типы данных могут быть добавлены к различным механизмам хранения, только MyISAM поддерживается для пространственных индексов R-дерева (см. документация здесь ), которые необходимы для получения необходимой производительности. Еще одно ограничение заключается в том, что пространственные типы данных работают только с числовыми данными, поэтому вы не можете использовать эту технику при запросах диапазона на основе строк.
Я не буду вдаваться в детали теории о том, как работают пространственные типы и как полезен пространственный индекс, но вы должны взглянуть на объяснение Джереми Коула здесь относительно того, как использовать пространственные типы данных и индексы для поиска GeoIP. Также посмотрите на комментарии, так как они поднимают некоторые полезные моменты и альтернативу, если вам нужна грубая производительность и вы можете отказаться от некоторой точности.
Основная предпосылка заключается в том, что мы можем взять начало / конец и использовать две из них для создания четырех различных точек, по одной для каждого угла прямоугольника с центром в районе 0,0 на сетке xy, а затем выполнить быстрый поиск в пространственный индекс, чтобы определить, находится ли конкретный момент времени, о котором мы заботимся, внутри прямоугольника или нет. Как упоминалось ранее, см. Объяснение Джереми Коула для более подробного обзора того, как это работает.
В вашем конкретном случае нам нужно будет сделать следующее:
1) Измените таблицу на таблицу MyISAM (обратите внимание, что вам не следует делать это, если вы не в полной мере осведомлены о последствиях такого изменения, таких как отсутствие транзакций и поведение блокировки таблиц, связанных с MyISAM).
alter table B engine = MyISAM;
2) Затем мы добавляем новый столбец, который будет содержать пространственные данные. Мы будем использовать тип данных многоугольника, так как нам нужно уметь удерживать полный прямоугольник.
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)
Пожалуйста, обратитесь к анализу Джереми Коула для деталей о преимуществах производительности этого метода по сравнению с предложением между ними.
Дайте мне знать, если у вас есть какие-либо вопросы.
Спасибо
-Dipin