Очень медленный запрос, когда сопоставление текстового поля не является пустой строкой

У меня есть очень простой запрос, который по сути таков:

Select * from my_table Where my_field != '';

В таблице около 40 000 строк, а столбец «my_field» — это текстовое поле (varchar 255).

Выполнение запроса занимает около 39 000 мс. Я предполагаю, потому что ему приходится просматривать каждую запись для вещей, которые не являются пустыми строками. Я проиндексировал столбец my_field, но ничего не изменилось.

На всякий случай, вот план запроса:

"Seq Scan on my_table  (cost=0.00..3468.91 rows=39744 width=459)"
"  Filter: ((my_field)::text <> ''::text)"

Какой мой лучший вариант здесь?

Объясните, проанализируйте:

"Seq Scan on my_table  (cost=0.00..3468.91 rows=39730 width=459) (actual time=0.021..13.763 rows=39714 loops=1)"
"  Filter: ((my_field)::text <> ''::text)"
"Total runtime: 14.856 ms"

Я добавил эти индексы

CREATE INDEX aa_idx ON my_table(my_field);
CREATE INDEX aa_idx ON my_table(my_field) WHERE my_field <> '';

Это Постгрес 9.1

Изменить: [2013-02-26 00:04GMT]

Будет ли какая-либо польза от создания раздела на «my_field» в качестве контрольного ограничения?

что-то вроде CHECK(my_field = '') и в разделе 2 CHECK(my_field != '')

Я предполагаю, что все, что у меня будет, это таблица с большим количеством строк? Но значит ли это, что запрос select != '' будет выполняться намного быстрее, даже если раздел будет содержать около 80% данных?

Я также изучил полнотекстовый поиск, но это казалось OTT для этого. Я также пытался сделать столбец целым числом 0 или 1 (bool), но это не повлияло на производительность (я думаю, потому что = 1 по-прежнему возвращает много строк?)


person TheStoneFox    schedule 24.02.2013    source источник
comment
1) Какова вероятность того, что запись имеет (не)пустое поле my_field: сколько записей удовлетворяет условию? 2) у вас есть статистика (вы запускали vacuum analyze после добавления индекса)?   -  person wildplasser    schedule 25.02.2013
comment
1) чаще всего, я бы сказал, около 75% полей соответствуют запросу. 2) да, после этого я провел полный анализ вакуума. Я также попытался добавить частичный индекс where my_field ‹› '', но это не имело никакого значения.   -  person TheStoneFox    schedule 25.02.2013
comment
Лучше всего показывать explain analyze, а не просто explain. Также: версия PostgreSQL? В какой локали находится ваша база данных? И, пожалуйста, покажите определение индекса, который вы добавили.   -  person Craig Ringer    schedule 25.02.2013
comment
Если 75% записей соответствуют запросу, будет уместно полное сканирование таблицы. При оценке в 18 строк на страницу было бы трудно найти страницу, без нужных строк.   -  person wildplasser    schedule 25.02.2013
comment
Итак, каковы мои варианты? Поскольку для запуска запроса требуется время (это часть более крупной процедуры удаления), я в основном нахожу все поля для удаления.   -  person TheStoneFox    schedule 25.02.2013
comment
варианты: 1) запустить запрос во второй раз (если второй запрос не быстрее, ваш Effective_cache_size установлен слишком низким) 2) заменить select * на select COUNT(*) (вывод громоздких результатов также влияет на время и пропускную способность)   -  person wildplasser    schedule 25.02.2013
comment
мой эффективный_кэш_размер составляет 512 МБ. Какой размер подходит для этой настройки?   -  person TheStoneFox    schedule 25.02.2013
comment
Хорошей настройкой является total_memory - xxx, где xxx — это память, необходимая для ОС и активных запущенных процессов.   -  person wildplasser    schedule 25.02.2013
comment
Итак, если на сервере 64 ГБ оперативной памяти, мне следует установить как минимум 48 ГБ?   -  person TheStoneFox    schedule 25.02.2013


Ответы (1)


Индекс вам не поможет. Я думаю, вам нужно найти лучший способ закрепить свое удаление.

Вы говорите, что для запуска требуется 39 секунд, но фактический план запроса, который вы предоставили, занимает 15 мс для запуска, что примерно в 2000 раз меньше. Мне трудно представить себе случай, когда кэширование могло бы так сильно помочь, если только мы не говорим об очень широких таблицах с большим количеством значений TOAST. Это говорит мне о том, что реальная проблема не в вашем выборе, а в другом месте вашего конвейера. Это может включать в себя расходы на поездку туда и обратно, а также то, как вы выполняете удаление.

Я рекомендую обратить внимание на консолидацию выписок. Это означало бы, что нужно избегать циклических обходов и использовать как можно больше логики в отдельных запросах. Поскольку вы не опубликовали полный контекст, я бы посоветовал вам изучить доступные для записи CTE для пакетной вставки, обновления и удаления без круговых поездок.

person Chris Travers    schedule 07.03.2013