2012-05-22 2 views
2

У меня есть запрос sqlite, который должен запускаться как можно быстрее. Запрос довольно прост, но я не знаю, как лучше всего индексировать таблицу для максимальной производительности.Лучшие индексы для этой таблицы и запроса?

Таблица называется «лексикон». Определение:

_id integer primary key 
word text 
frequency integer 
lset integer 
rset integer 

запрос:

SELECT word,frequency FROM lexicon WHERE lset>? AND rset<? ORDER BY frequency DESC LIMIT ? 

Я проиндексированы все отдельные столбцы, но я подозреваю, составные индексы могут быть лучше, но какая комбинация? И должны ли индексы на lset и rset быть восходящими или нисходящими?

EDIT: lset и rset - вложенные значения множества, представляющие древовидную структуру. Поэтому все значения lset и rset взаимно уникальны и отлично распределены. Кроме того, в любой строке lset < rset.

Заранее спасибо ...

+2

Как всегда, это зависит! В этом случае селективность предикатов 'lset' и' rset' будет критической. Скорее всего, 'lset>?' Вернет большее или меньшее количество записей, чем 'rset

+0

Большой вопрос. Я должен был упомянуть, что lset и rset представляют собой вложенные значения множества, представляющие древовидную структуру. Поэтому все значения lset и rset взаимно уникальны и отлично распределены с диапазоном 1- 2 * N (где N - количество строк в таблице). –

+0

@Barry: Вы (также) означаете, что следующее всегда верно ?: 'lset <= rset' –

ответ

1

Ваш запрос (с небольшими изменениями в названиях):

SELECT word,frequency 
FROM lexicon 
WHERE lset > @LeftSide 
    AND rset < @RightSide 
ORDER BY frequency DESC 
LIMIT @Num 

Вы используете модель вложенных множеств, поэтому он может быть переписано в виде:

SELECT word,frequency 
FROM lexicon 
WHERE lset > @LeftSide   --- both `lset` here 
    AND lset < @RightSide   --- and here 
ORDER BY frequency DESC 
LIMIT @Num 

Они также могут быть как rset. Пока ваши данные не нарушают модель вложенного набора, оба будут работать и давать одинаковые результаты. Таким образом, запрос может потребоваться индекс покрытия на 3 колонки:

(lset, frequency, word) 

Он будет использовать индекс для идентификации (возможно тысячи) строк, которые попадают в (@LeftSide,@RightSide) диапазона, а затем использовать FileSort, чтобы найти (@ Num) слова с максимальной частотой.

В некоторых случаях индекс на (frequency DESC, lset, word) может быть лучше (это действительно зависит от значений параметров), поэтому хорошо, если у вас есть этот индекс. Но я не могу ответить, будет ли SQLite набирать лучший индекс для каждого экземпляра.

В зависимости от того, сколько рядов попадает в этот диапазон, оно может работать от хорошо до не очень хорошо. Но я не вижу простого способа оптимизировать этот запрос.

+0

Спасибо за оптимизацию запроса. Теперь я вижу, что rset действительно не нужно. Я обновил запрос и проиндексировал таблицу, как вы предлагали, но она все еще недостаточно быстро. Я подозреваю, как и вы, что его нельзя оптимизировать дальше. –

+0

Отличная новость: я использовал неправильный индекс (колонки были в неправильном порядке), и после правильного их расчета запрос был быстрее на 5-10 раз. Я думаю, теперь это достаточно быстро для моих целей. :) :) :) –

+0

@Barry: Я разместил связанный с этим вопрос на dba.se: [Выполнение запроса с условием и порядком диапазона] (http://dba.stackexchange.com/questions/18289/performance- из-запроса-с-диапазон условия и порядка по дороге). Не стесняйтесь следовать этому и комментировать там. –

2

Если SQLite ведет себя simlarly другим DBMSes в связи с этим, вы будете нуждаться в составной индекс по ...

{lset, rset DESC, frequency DESC} 

... в этом особом порядке и с этими конкретными предложениями DESC.

Посмотрите на this article, чтобы узнать больше о восходящих/низовых индексах.


И да, как уже упоминалось @DanielRenshaw, вы можете включить word в конце индекса, просто позволить index-only scan. Это называется индексом покрытия.

(Поскольку индекс кластеризации уже охватывает всю область, нет никакого смысла делать что для такого индекса.)

3

Это будет зависеть от статистики ваших данных.

Вы могли бы попытаться создать индексы на каждой комбинации lset, rset и frequency найти лучший случай, но вы обязательно то есть реальные данные в таблице.
- (lset, rset, frequency)
- (rset, lset, frequency)
- (lset, frequency, rset)
- (rset, frequency, lset)
- (frequency, lset, rset)
- (frequency, rset, lset)

Преимущество наличия frequency состоит в том, что он уже подготовлен к вашим статьям ORDER BY и LIMIT.

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

Также имеет значение, какое поле ограничивает ваши записи самым быстрым. Если фильтр lset < x уменьшает набор до 0.01% первоначального размера, поместите этот фильтр первым в свой индекс.

Но, во всяком случае, фильтрация lset < X and rset > y будет невозможна индексировать очень хорошо.

+3

Возможно, стоит отметить, что если Sqlite ведет себя как другие СУБД, добавив слово «слово» в качестве последнего столбца в индексе, заставит индекс охватить все необходимые поля и избежать необходимости искать этот столбец в другом месте. Это не помогло бы, если бы этот индекс группировал таблицу. –

+0

@ DanielRenshaw - Согласовано. Поиск поля данных, которое не находится в индексе, похоже на добавление дополнительного соединения ... 'JOIN theIndex On blah JOIN theTable ON theIndex.PK = theTable.PK'. Включение необходимых полей в индекс, таким образом, устраняет эти накладные расходы. * (За исключением кластеризованных индексов, где Таблица является индексом.) * – MatBailie

+0

@Dems Я не уверен, поддерживает ли SQLite это, но в «больших» СУБД вы можете смешать «ориентацию» компонентов индекса, так что 'lset>? И rset

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