Низкая производительность при использовании пространственных индексов в MySQL

13

Повторно отправьте вопрос о переполнении стека, когда было высказано предположение, что это будет лучший форум.

Я пытаюсь провести небольшой эксперимент с использованием набора данных, который не является геопространственным, но подходит ему достаточно хорошо, и результаты меня несколько тревожат. Набор данных является геномными данными, например, Человеческий Геном, где у нас есть область ДНК, где такие элементы, как гены, занимают определенные начальные и конечные координаты (наша ось X). У нас есть несколько областей ДНК (хромосом), которые занимают ось Y. Цель состоит в том, чтобы вернуть все элементы, которые пересекают две координаты X вдоль одной координаты Y, например LineString (START 1, END 2).

Теория казалась здравой, поэтому я внедрил ее в существующий геномный проект на базе MySQL и придумал структуру таблицы, например:

CREATE TABLE `spatial_feature` (
  `spatial_feature_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `external_id` int(10) unsigned NOT NULL,
  `external_type` int(3) unsigned NOT NULL,
  `location` geometry NOT NULL,
  PRIMARY KEY (`spatial_feature_id`),
  SPATIAL KEY `sf_location_idx` (`location`)
) ENGINE=MyISAM;

external_idпредставляет идентификатор объекта, который мы закодировали в этой таблице, и external_typeкодирует его источник. Все выглядело хорошо, и я добавил некоторые предварительные данные (30 000 строк), которые, казалось, работали хорошо. Когда это число превысило отметку в 3 миллиона строк, MySQL отказался использовать пространственный индекс и стал медленнее, когда его заставили его использовать (40 секунд против 5 секунд при полном сканировании таблицы). Когда было добавлено больше данных, индекс начал использоваться, но снижение производительности сохранялось. При принудительном отключении индекса запрос сократился до 8 секунд. Используемый мной запрос выглядит так:

select count(*)
from spatial_feature
where MBRIntersects(GeomFromText('LineString(7420023 1, 7420023 1)'), location);

Данные, входящие в этот список, будут очень плотными по измерениям Y (представьте себе, что вы записали положение каждого здания, телефонной будки, почтового ящика и голубя на очень длинной дороге). Я провел тесты того, как R-индексы ведут себя с этими данными в Java, а также другие специалисты в этой области успешно применили их к форматам плоских файлов. Однако никто не применил их к базам данных AFAIK, что является целью этого теста.

Кто-нибудь видел подобное поведение при добавлении больших объемов данных в пространственную модель, которая не очень разнородна по определенной оси? Проблема сохраняется, если я переверну использование координат. Я запускаю следующую настройку, если это является причиной

  • MacOS 10.6.6
  • MySQL 5.1.46
andeyatz
источник

Ответы:

5

MySQL, как и PostGIS, хранит свои данные пространственного индекса в структуре R-дерева, чтобы быстро находить нужные данные. R-дерево, как и B-дерево, организовано таким образом, что оно оптимизировано для извлечения только небольшой части всех данных в таблице. На самом деле быстрее игнорировать индекс для запросов, которые должны прочитать большой раздел таблицы, чтобы вернуть данные или выполнить огромное объединение, классический случай, который приводит к тому, что многие базы данных [авторы] жалуются на запрос, который возвращает половину их таблица "не использует новый индекс, который они только что создали."

От http://rickonrails.wordpress.com/2009/03/30/big-ole-mysql-spatial-table-optimization-tricks/

Если вы можете поместить все данные таблицы в память, ваша производительность будет хорошей. Если / когда вам нужно начать чтение с диска, производительность быстро ухудшится. Вы делали шаблоны использования памяти вашего экземпляра mysql для двух случаев: 30 тыс. Строк против 3000 тыс. Строк?

tmarthal
источник
Я думаю, что это может быть ближе к вопросу. TBH это R-индекс, который я хочу; другая пространственная математика является хорошим бонусом, поскольку это должно быть сделано на уровне API под старой системой. Я попытался немного настроить, но увеличение ключевых буферов не помогло (другие буферы здесь не помогут, как буфер таблиц, так как это запрос на 1 таблицу на моем персональном сервере). Странно то, что MySQL забивает мою машину в землю при выполнении запросов (100% во время выполнения запроса). Тем не менее, он выполняет полное сканирование таблицы, так что, может быть, это не так уж и странно
andeyatz
5

Что-то должно быть не так с вашей установкой mysql или настройками .ini. Только что проверил геопространственный индекс на моем старом Mac (10.6.8 / MySQL 5.2). Эта конфигурация похожа на вашу, и я протестировал большой дамп геоданных ( 9 миллионов записей ). Я сделал этот запрос:

SET @radius = 30;
SET @center = GeomFromText('POINT(51.51359 7.465425)');
SET @r = @radius/69.1;
SET @bbox = CONCAT('POLYGON((', 
  X(@center) - @r, ' ', Y(@center) - @r, ',', 
  X(@center) + @r, ' ', Y(@center) - @r, ',', 
  X(@center) + @r, ' ', Y(@center) + @r, ',', 
  X(@center) - @r, ' ', Y(@center) + @r, ',', 
  X(@center) - @r, ' ', Y(@center) - @r, '))' 
);

SELECT geonameid, SQRT(POW( ABS( X(point) - X(@center)), 2) + POW( ABS(Y(point) - Y(@center)), 2 ))*69.1 
AS distance
FROM TABLENAME AS root
WHERE Intersects( point, GeomFromText(@bbox) ) 
AND SQRT(POW( ABS( X(point) - X(@center)), 2) + POW( ABS(Y(point) - Y(@center)), 2 )) < @r 
ORDER BY distance; 

Это заняло всего 0,0336 сек.

Я использую приведенный выше запрос, например, для сравнения таблиц, в которых таблица, из которой взяты только значения широты / долготы для @center, имеет простой INDEX из city_latitude / city_longitude и 9-12 Mio. Таблица от geonames.org имеет геопространственный индекс.

И я просто хотел добавить, что когда кто-нибудь вставляет большие данные в таблицу, было бы более целесообразно добавить индекс после INSERT. Если нет, это займет больше времени для каждой строки, которую вы добавляете ... [но это не важно]

sebilasse
источник
Вау, это действительно хорошо. Теперь я не уверен, что я делал неправильно в моих собственных тестах. Одна вещь, которая может вызывать проблему, - это природа моих наборов данных по сравнению с более традиционными наборами геопространственных данных. Тем не менее, я просто догадываюсь и не имею для этого никаких оснований. Замечательно видеть, что вам не нужно вводить индекс в память, чтобы получить скорость.
andeyatz
Предложение WHERE с радиусом может отфильтровывать большую часть таблицы от использования индекса.
tmarthal
2

Задумывались ли вы о том, чтобы разбить его на два 1D столбца вместо одного 2D столбца?

Оптимизатор может задушить все подобные данные, и может помочь наличие двух столбцов с большим разнообразием.

То, что вы также можете проверить, это порядок, в котором элементы проверяются. У меня была проблема в Oracle Spatial, где я искал по Фамилии и фильтру IN_REGION. Oracle решила, что самым быстрым способом будет использовать фамилию, а затем выполнить проверку региона. Позвольте мне сказать вам, что проверка всех Робинсонов в Кливленде в регионе идет медленно . Я помню, что мне пришлось передать специфический аргумент Oracle, чтобы сначала он использовал пространственный индекс.

Марк Робинсон
источник
К сожалению, 1 измерение гораздо менее заселено, чем другое измерение. Чтобы поместить это в контекст, человеческий геном имеет 24 уникальных хромосомы (22 пары и две половые хромосомы) вместе с пакетом данных, который был собран на разных уровнях. Это означает, что если вы сопоставляете элементы с базовым вариантом использования, то есть только 24 уникальных идентификатора в одном измерении. Первоначальная надежда заключалась в том, что индекс R-дерева мог бы выполнять не только более эффективные проверки перекрывающихся диапазонов, но и различать эти области в одном запросе.
andeyatz