Работает ли многостолбцовый индекс для отдельных столбцов? - PullRequest
42 голосов
/ 28 апреля 2009

У меня есть (например) индекс:

CREATE INDEX someIndex ON orders (customer, date);

Этот индекс ускоряет только те запросы, для которых используются customer и date , или он ускоряет запросы для одного столбца, подобного этому?

SELECT * FROM orders WHERE customer > 33;

Я использую SQLite.


Если ответ «да», то почему можно создать более одного индекса для таблицы?


Еще один вопрос: насколько быстрее комбинированный индекс по сравнению с двумя отдельными индексами при использовании обоих столбцов в запросе?

Ответы [ 3 ]

38 голосов
/ 28 апреля 2009

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

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

Используя приведенный вами пример, если вы запустили запрос:

SELECT * from orders where customer > 33 && date > 99

Sqlite сначала получит все результаты, используя бинарный поиск по всей таблице, где customer> 33. Затем он выполнит бинарный поиск только по тем результатам, которые ищут дату> 99.

Если вы выполняете один и тот же запрос с двумя отдельными индексами по клиенту и дате, Sqlite придется дважды выполнить двоичный поиск по всей таблице, сначала для клиента, а затем для даты.

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

Для получения дополнительной информации см. Это: http://www.sqlite.org/optoverview.html

5 голосов
/ 28 апреля 2009

Я почти уверен, что это сработает, да, в любом случае это работает в MS SQL Server.

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

Марк

3 голосов
/ 29 апреля 2011

Я обычно использую комбинированные индексы для сортировки данных, которые я хочу разбить на страницы или запрашивать «потоково».

Предполагается, что клиент может сделать более одного заказа ... и существуют клиенты от 0 до 11, и существует несколько заказов на каждого клиента, все они вставлены в случайном порядке. Я хочу отсортировать запрос по номеру клиента и дате. Вы также должны отсортировать поле id в последнюю очередь, чтобы разделить наборы, когда у клиента несколько идентичных дат (даже если это может никогда не произойти).

sqlite> CREATE INDEX customer_asc_date_asc_index_asc ON orders
          (customer ASC, date ASC, id ASC);

Получить страницу 1 отсортированного запроса (не более 10 элементов):

sqlite> SELECT id, customer, date FROM orders
          ORDER BY customer ASC, date ASC, id ASC LIMIT 10;

2653|1|1303828585
2520|1|1303828713
2583|1|1303829785
1828|1|1303830446
1756|1|1303830540
1761|1|1303831506
2442|1|1303831705
2523|1|1303833761
2160|1|1303835195
2645|1|1303837524

Получить следующую страницу:

sqlite> SELECT id, customer, date FROM orders WHERE
          (customer = 1 AND date = 1303837524 and id > 2645) OR
          (customer = 1 AND date > 1303837524) OR
          (customer > 1)
          ORDER BY customer ASC, date ASC, id ASC LIMIT 10;

2515|1|1303837914
2370|1|1303839573
1898|1|1303840317
1546|1|1303842312
1889|1|1303843243
2439|1|1303843699
2167|1|1303849376
1544|1|1303850494
2247|1|1303850869
2108|1|1303853285

И так далее ...

Наличие индексов сокращает сканирование индексов на стороне сервера, если в противном случае вы используете запрос OFFSET в сочетании с LIMIT. Время запроса увеличивается, и чем сильнее смещение, тем жестче поиск дисков. Использование этого метода устраняет это.

Рекомендуется использовать этот метод, если вы планируете объединить данные позже, но вам нужен только ограниченный набор данных для каждого запроса. Соединитесь с SUBSELECT, как описано выше, чтобы уменьшить накладные расходы памяти для больших таблиц.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...