2017-01-09 1 views
2

У меня есть таблица с полями 'lat' и 'lng'. Оба они почти непрерывны, а это означает, что они не повторяются. Это заставило меня поверить, что создание многоколоночного индекса для lat и lng действительно не помогло бы мне. То, что я хотел бы сделать это:mysql geolat geolng multi проиндексированный запрос

Сделать индекс и широты и LNG, а затем выполнить запрос типа:

select from tableName where 
lat >= 13.1232 and lat <=14.123 and 
lng >=-80.123 and lng <=-79.232 and 
name like '%greg%' 

и MySQL выполнить этот процесс:

  1. выбрать все латы между 14.1232 и 13.123 (это должно быть проиндексировано, и быстро)

  2. в пределах группы, что шаг # 1 найдено, выполнить шаг # 2: найти LNGS < = -80,123 и ЛНГС> = -79,232 (это также должно быть проиндексированы и очень быстро)

3. в пределах группы, созданной с шагом 1 и # # 2 ... выполнять более трудоемкий поиск по ключевому слову.

Как это сделать? Я почти уверен, что первая часть запроса (индексированный лат) сужает меня для меня ... но после этого я не уверен ... и это то, что я изо всех сил пытался найти в docs

+0

Похоже, вы уже это сработало. Вы добавили индекс в столбцы lat и lng, или это то, что вы спрашиваете, как это сделать? – mba12

+0

им просто интересно, как mysql обрабатывает порядок его запроса ... Я уверен, что первая часть запроса (индексированная лат) сужает его, но как насчет второй части запроса? (indexed lng) – rikkitikkitumbo

ответ

2

MySQL обрабатывает обычные индексы B-дерева, как в большинстве реализаций: Индекс помогает только условие диапазона на крайних левых столбцов в индексе.

Аналогия, которую я использую, - это телефонная книга. Если я ищу конкретную фамилию, имя-пара, как «Смит, Джон», помогает индекс. Мой поиск фамилии «Смит» быстрый, и в «Смитах» поиск «Джона» очень быстрый.

Но если я ищу условия диапазона, такие как «все люди, чья фамилия начинается с« S », тогда я получаю подмножество телефонной книги, но не все люди с именем« Джон »сортируются вместе. Они разбросаны по подмножеству, выбранному мной по фамилии.

Именно по этой причине MySQL выполняет поиск индекса B-дерева до первого условия диапазона, а затем не использует индекс дальше. Вы можете создавать условия для другого измерения, но он будет выполнять ручной поиск по всем строкам, соответствующим первому измерению.

Другими словами, даже если у вас есть составной индекс на (lat, long), MySQL не будет использовать long часть индекса:

select ... from tableName 
where lat >= 14.1232 and lat <=13.123 /* index-assisted */ 
    and lng >=-80.123 and lng <=-79.232 /* full scan */ 
    and name like '%greg%'    /* pattern search never uses index anyway */ 

(Кстати, ваш лат состояние никогда не может быть правдой, как вы написали, но я предполагаю, что вы имеете в виду номера, которые нужно обратить вспять.)

Это делает неэффективным выполнение широты & долготы, так как оба выполняют поиск по целому ряду значений.

По этой причине у MySQL есть другой тип индекса, который не является индексом B-дерева. Это индекс SPATIAL, который поддерживает несколько условий диапазона.

CREATE TABLE mytable (
    name TEXT NOT NULL, 
    coord POINT NOT NULL, 
    SPATIAL INDEX (coord) 
); 

INSERT INTO mytable (name, coord) 
VALUES ('name', ST_GeomFromText('POINT(14.0 -80)')); 

SELECT name FROM mytable 
WHERE MBRContains(
    ST_GeomFromText('Polygon((
    13.123 -80.123, 
    14.1232 -80.123, 
    14.1232 -79.232, 
    13.123 -79.232, 
    13.123 -80.123))'), 
    coord); 

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

Подробнее об этом здесь: http://dev.mysql.com/doc/refman/5.7/en/using-spatial-data.html

+0

это отличный ответ ... но он также немного поглядывает на мою голову, поэтому на этом этапе я собираюсь придерживаться простого индекса двоичного дерева по долготе. – rikkitikkitumbo

+1

'INDEX (долгота)' будет не лучше, чем 'INDEX (широта)'. Оптимизатор не будет использовать оба. –

+0

да, согласен. Я думаю, что это еще одно решение, если вам абсолютно нужно было сузить ваш db с индексированием: создать некоторую систему сетки ящиков, а затем сохранить ваши данные с определенным именем поля при вставке ... а затем при запросе db: «дайте мне все данные с boxField =« x123y123 »или независимо от вашей грид-системы. BoxField можно индексировать ... – rikkitikkitumbo

1

Если вы абсолютно хотите, чтобы каждое предложение where ограничивало набор результатов, чтобы вы могли попробовать что-то подобное, но оптимизатор sql мог бы изменить вещи под обложкой. Я считаю, что хороший индекс или два по-прежнему ваш лучший выбор, но я считаю, что это то, о чем вы просите. Я рекомендую Explain Plan оптимизировать ваши запросы.

select * from 
(
    select * from 
     (
     select * from tableName 
     where lat >= 14.1232 and lat <=13.123 
     ) 
    where lng >=-80.123 and lng <=-79.232 
) 
where name like '%greg%' 
+2

ok ... сделал еще несколько исследований и испытаний ... и насколько я могу судить ... mysql использует только первый индекс. в этом случае вы технически создаете новые таблицы «на лету» (и даете им псевдонимы) ... и вы не указали индексы на этих «на лету» таблицах, поэтому, согласно EXPLAIN, единственным используемым индексом является ' lat '. Похоже, единственный способ сделать это - «жесткий» способ, которым Билл Карвин говорит о – rikkitikkitumbo

+2

@rikkitikkitumbo, правильно. Это решение с использованием подзапросов не имеет значения. Фактически, это, вероятно, сделает запрос медленнее, поскольку он должен создавать временные таблицы. –

Смежные вопросы