Индексация SQL на varchar - PullRequest
       56

Индексация SQL на varchar

14 голосов
/ 13 апреля 2010

У меня есть таблица, столбцы которой varchar(50) и float. Мне нужно (очень быстро) посмотреть получить float, связанный с данной строкой. Даже с индексированием это довольно медленно.

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

Есть ли что-нибудь, что можно получить, добавив это целое число в таблицу, проиндексировав ее и использовав такой запрос:

SELECT floatval FROM mytable WHERE phrase=givenstring AND assoc=givenint

Это Postgres, и если вы не могли бы сказать, у меня очень мало опыта работы с базами данных.

Ответы [ 5 ]

18 голосов
/ 13 апреля 2010

Ключи в столбцах VARCHAR могут быть очень длинными, что приводит к меньшему количеству записей на страницу и большей глубине (больше уровней в B-Tree). Более длинные индексы также увеличивают коэффициент пропадания кэша.

Сколько строк в среднем соответствует каждому целому числу?

Если их относительно мало, вы можете создать индекс только для целочисленного столбца, а PostgreSQL выполнит тонкую фильтрацию записей:

CREATE INDEX ix_mytable_assoc ON mytable (assoc);

SELECT  floatval
FROM    mytable
WHERE   assoc = givenint
        AND phrase = givenstring

Вы также можете рассмотреть возможность создания индекса для строковых хэшей:

CREATE INDEX ix_mytable_md5 ON mytable (DECODE(MD5(phrase), 'HEX'));

SELECT  floatval
FROM    mytable
WHERE   DECODE(MD5(phrase), 'HEX') = DECODE(MD5('givenstring'), 'HEX')
        AND phrase = givenstring -- who knows when do we get a collision?

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

4 голосов
/ 14 апреля 2010

Я бы порекомендовал просто хеш-индекс:

create index mytable_phrase_idx on mytable using hash(phrase);

Таким образом, запросы как

select floatval from mytable where phrase='foo bar';

будет очень быстро. Проверьте это:

create temporary table test ( k varchar(50), v float);
insert into test (k, v) select 'foo bar number '||generate_series(1,1000000), 1;
create index test_k_idx on test using hash (k);
analyze test;
explain analyze select v from test where k='foo bar number 634652';
                                                   QUERY PLAN                                                    
-----------------------------------------------------------------------------------------------------------------
 Index Scan using test_k_idx on test  (cost=0.00..8.45 rows=1 width=8) (actual time=0.201..0.206 rows=1 loops=1)
   Index Cond: ((k)::text = 'foo bar number 634652'::text)
 <b>Total runtime: 0.265 ms</b>
(3 rows)
0 голосов
/ 14 апреля 2010

Краткий ответ: да, будет много чего. По крайней мере, до тех пор, пока у вас мало обновлений, но вполне вероятно, что накладные расходы даже там не будут заметны.

0 голосов
/ 13 апреля 2010

Не помешает попытаться добавить int и сделать ваш индекс для int, varchar и include float - это будет достаточно эффективно и эффективно - не уверен, если Postgres включит столбцы - если он просто не добавляет его в сам индекс.

Есть несколько других приемов, на которые вы могли бы обратить внимание (я не знаком со всеми функциями Postgres, поэтому я дам их по имени SQL Server):

Индексированные представления - вы можете эффективно материализовать представление, объединяющее несколько таблиц, - чтобы вы могли присоединить ваш varchar к вашему int и иметь свой индекс для int, varchar и float

Включенные столбцы - вы можете включить столбцы в индекс, чтобы гарантировать, что индекс покрывает - т.е. иметь индекс на varchar include (float) - если ваш индекс не покрывает, оптимизатору запросов все равно придется использовать индекс, а затем выполните поиск по закладкам, чтобы получить оставшиеся данные.

0 голосов
/ 13 апреля 2010

При объявлении индекса на (phrase, assoc, floatval) вы получите «покрывающий индекс», который позволяет выполнить запрос, опубликованный в вопросе, даже не обращаясь к таблице. Предполагая, что либо phrase, либо assoc очень избирательно (не много строк имеют одинаковое значение для поля), создание индекса только для этого поля должно привести к почти одинаковой производительности.

Как правило, вы хотите ограничить число индексов наименьшим набором, который обеспечивает частые запросы до желаемой производительности. Для каждого индекса, добавляемого в таблицу, вы платите некоторое дисковое пространство, но, что более важно, вы платите цену за то, чтобы СУБД выполняла больше работы над каждым INSERT в таблице.

...