В моем решении есть одна оговорка:
1) Предостережение в этом решении заключается в том, что вы должны использовать движок MyISAM для таблицы событий. Если вы не можете использовать MyISAM, то это решение не будет работать, поскольку для пространственных индексов поддерживается только MyISAM.
Итак, при условии, что вышеприведенное не является для вас проблемой, следующее должно работать и обеспечивать хорошую производительность:
В этом решении используется поддержка MySQL для пространственных данных (см. документацию здесь ). Хотя пространственные типы данных могут быть добавлены к различным механизмам хранения, только MyISAM поддерживается для пространственных индексов R-дерева (см. документация здесь ), которые необходимы для получения необходимой производительности. Еще одно ограничение заключается в том, что пространственные типы данных работают только с числовыми данными, поэтому вы не можете использовать эту технику при запросах диапазона на основе строк.
Я не буду вдаваться в детали теории о том, как работают пространственные типы и как полезен пространственный индекс, но вы должны взглянуть на объяснение Джереми Коула здесь относительно того, как использовать пространственные типы данных и индексы для поиска GeoIP. Также посмотрите на комментарии, так как они поднимают некоторые полезные моменты и альтернативу, если вам нужна грубая производительность и вы можете отказаться от некоторой точности.
Основная предпосылка заключается в том, что мы можем взять начало / конец и использовать две из них для создания четырех различных точек, по одной для каждого угла прямоугольника с центром в районе 0,0 на сетке xy, а затем выполнить быстрый поиск в пространственный индекс, чтобы определить, находится ли конкретный момент времени, о котором мы заботимся, внутри прямоугольника или нет. Как упоминалось ранее, см. Объяснение Джереми Коула для более подробного обзора того, как это работает.
В вашем конкретном случае нам нужно будет сделать следующее:
1) Измените таблицу на таблицу MyISAM (обратите внимание, что вам не следует делать это, если вы не в полной мере осведомлены о последствиях такого изменения, таких как отсутствие транзакций и поведение блокировки таблиц, связанных с MyISAM).
alter table events engine = MyISAM;
2) Затем мы добавляем новый столбец, который будет содержать пространственные данные. Мы будем использовать тип данных многоугольника, так как нам нужно уметь удерживать полный прямоугольник.
alter table events add column time_poly polygon NOT NULL;
3) Затем мы заполняем новый столбец данными (имейте в виду, что любые процессы, которые обновляют или вставляют в события таблицы, необходимо изменить, чтобы убедиться, что они также заполняют новый столбец). Поскольку начальный и конечный диапазоны являются временами, нам необходимо преобразовать их в числа с помощью функции unix_timestamp (см. Документацию здесь , чтобы узнать, как она работает).
update events 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 events add SPATIAL KEY `IXs_time_poly` (`time_poly`);
5) Затем вам нужно будет использовать следующий выбор, чтобы использовать пространственный индекс при запросе данных.
SELECT *
FROM events force index (IXs_time_poly)
WHERE MBRCONTAINS(events.time_poly, POINTFROMWKB(POINT(unix_timestamp('2009-02-18 16:27:12'), 0)));
Индекс силы предназначен для 100% уверенности, что MySQL будет использовать этот индекс для поиска. Если все прошло хорошо, объяснение вышеупомянутого выбора должно показать что-то похожее на следующее:
mysql> explain SELECT *
-> FROM events force index (IXs_time_poly)
-> on MBRCONTAINS(events.time_poly, POINTFROMWKB(POINT(unix_timestamp('2009-02-18 16:27:12'), 0)));
+----+-------------+-------+-------+---------------+---------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------------+---------+------+------+-------------+
| 1 | SIMPLE | B | range | IXs_time_poly | IXs_time_poly | 32 | NULL | 1 | Using where |
+----+-------------+-------+-------+---------------+---------------+---------+------+------+-------------+
1 row in set (0.00 sec)
Пожалуйста, обратитесь к анализу Джереми Коула для деталей о преимуществах производительности этого метода по сравнению с предложением между ними.
Дайте мне знать, если у вас есть какие-либо вопросы.
Спасибо
-Dipin