Подтвердить что ты не робот

Индексирование SQL на varchar

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

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

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

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

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

4b9b3361

Ответ 1

Ключи в столбцах 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 байтов, поэтому индексные клавиши будут намного короче, сохраняя при этом почти полную селективность.

Ответ 2

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

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)
 Total runtime: 0.265 ms
(3 rows)

Ответ 3

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

Ответ 4

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

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

Ответ 5

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

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

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

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