Производительность SQL, что выполняется быстрее в условиях SELECT и WHERE - PullRequest
2 голосов
/ 14 сентября 2011

ОБНОВЛЕНИЕ: Дерьмо! это не целое число, это разные символы (10)

При выполнении такого запроса используется индекс

SELECT t."FieldID"
FROM table t
WHERE t."FieldID" = '0123456789'

Но не использует индекс, если я выполню это

SELECT t."FieldID"
FROM table t
WHERE t."FieldID" LIKE '01%'

или это

SELECT t."FieldID"
FROM table t
WHERE "substring"(t."FieldID", 0, 3) = '01'

также это

SELECT t."FieldID"
FROM table t
WHERE t."FieldID" ~ '^01'

Мой индекс выглядит так

CREATE UNIQUE INDEX fieldid_index
  ON "table"
  USING btree
  ("FieldID");

Запуск PostgreSQL 7.4 (обновление Yep)

Я оптимизирую свой запрос и хотел узнать, есть ли какой-либо выигрыш в производительности, используя один из трех типов выражений в предложении SELECT или WHERE в выражении.

ПРИМЕЧАНИЕ. Запрос, который выполняется с этими ограничениями стиля, возвращает около 200 000 записей

Пример данных: символ варьируется (10) : 0123456789 и также индексируется

1. (Подстроки)

SELECT CASE
    WHEN "substring"(t."FieldID"::text, 0, 3) = '01'::text         
    THEN 'Found Match'::text
    ELSE NULL::text
END AS matching_group

2. (Как)

SELECT CASE
    WHEN t."FieldID"::text LIKE '01%'         
    THEN 'Found Match'::text
    ELSE NULL::text
END AS matching_group

3. (RegEx)

SELECT CASE
    WHEN t."FieldID" ~ '^01'         
    THEN 'Found Match'::text
    ELSE NULL::text
END AS matching_group

Также есть ли какие-либо преимущества в производительности при использовании одного над другим в предложении WHERE?

1. (Подстроки)

WHERE CASE
    WHEN "substring"(t."FieldID"::text, 0, 3) = '01'::text         
    THEN 1
    ELSE 0
END = 1

2. (Как)

WHERE CASE
    WHEN t."FieldID"::text LIKE '01%'         
    THEN 1
    ELSE 0
END = 1

3. (RegEx)

WHERE CASE
    WHEN t."FieldID" ~ '^01'         
    THEN 1
    ELSE 0
END = 1

Повысит ли использование одного параметра в SELECT и другого в предложении WHERE?

Ответы [ 4 ]

3 голосов
/ 14 сентября 2011

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

ANALYZE your_first_table;
-- ANALYZE other tables used in this query.
EXPLAIN ANALYZE
SELECT ...

См. Документы для Изучение использования индекса .

Возможно, вы сможете воспользоваться индексами для выражений или частичными индексами . PostgreSQL 7.4 поддерживает как индексы для выражений, так и частичные индексы. Для тестирования вы можете отказаться от определенных видов планов запросов . (Также в 7.4.)

Индекс на основе выражений, который может работать для вас:

create index firsttwochars
on your-table-name (substring(your-column-name from 1 for 2));

Но вам все равно нужно проверить свои запросы, чтобы увидеть, действительно ли они используют индекс. (Будь они sargable .) Это может сработать.

select your-column-name 
from your-table-name 
where substring(your-column-name from 1 for 2) = '01'

План запроса без индекса по первым двум символам. (В моей тестовой таблице используются случайные текстовые имена пользователей, поэтому я искал «ab» вместо «01».)

Seq Scan on substring  (cost=0.00..205.00 rows=50 width=11) (actual time=0.315..4.377 rows=14 loops=1)
  Filter: (substring((username)::text, 1, 2) = 'ab'::text)
Total runtime: 4.414 ms

План запроса с индексом первых двух символов.

Bitmap Heap Scan on substring  (cost=4.36..37.61 rows=14 width=11) (actual time=0.036..0.056 rows=14 loops=1)
  Recheck Cond: (substring((username)::text, 1, 2) = 'ab'::text)
  ->  Bitmap Index Scan on firsttwochars  (cost=0.00..4.36 rows=14 width=0) (actual time=0.028..0.028 rows=14 loops=1)
        Index Cond: (substring((username)::text, 1, 2) = 'ab'::text)
Total runtime: 0.098 ms
3 голосов
/ 14 сентября 2011

Лично я считаю, что тому, кто создает подобные проблемы, нельзя разрешать использовать слово «производительность». Ограничения (такие как в предложении WHERE) для текстового представления содержимого числового поля (возможно, даже ключевого поля) указывают на плохой дизайн, ИМХО.

Если бы это были мои данные, я бы добавил в запись поле флага, указывающее, что хотел / не хотел в запросе xyz. Можно даже положить его в отдельный стол. Я предпочитаю добавлять (избыточный?) Столбец к созданию целого индекса на основе мусора GW-basic-substring.

1 голос
/ 14 сентября 2011

В SQL Server версия с LIKE '01%' может быть sargable.Он на самом деле преобразует эти LIKE запросы без использования подстановочных знаков для диапазонов запросов.

План выполнения показывает предикат поиска как YourCol >= '01' AND YourCol < '02', возможно, подобный вид перезаписи может помочь в Postgresql?

1 голос
/ 14 сентября 2011

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

Для предложения WHERE можно добавить индекс выражения, например

CREATE INDEX foo ON sometable ((
CASE
    WHEN "substring"("FieldID"::text, 0, 3) = '01'::text         
    THEN 1
    ELSE 0
END
));

, но селективность такого логического индекса, вероятно, будет достаточно плохой, чтобы неинтересует планировщик.Было бы лучше переписать предложение WHERE просто на

WHERE "substring"("FieldID"::text, 0, 3) = '01'::text

, а затем проиндексировать его.

Для случаев LIKE и регулярных выражений индекс text_pattern_ops можно рассматривать какЧто ж;см. документацию .

В общем, я думаю, что у вас есть работа по очистке этого запроса.

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