REINDEX опасно?

17

Я пытался COUNT(*)создать таблицу с 150000 строк, которая имеет первичный ключ. Это инструмент около 5 минут, поэтому я понял, что это проблема индексации.

Ссылаясь на руководство PostgreSQL :

REINDEX похож на удаление и воссоздание индекса в том, что содержимое индекса перестраивается с нуля. Однако соображения блокировки довольно разные. REINDEX блокирует записи, но не чтения родительской таблицы индекса. Он также принимает эксклюзивную блокировку для конкретного обрабатываемого индекса, который блокирует чтения, которые пытаются использовать этот индекс (...). Последующий CREATE INDEX блокирует записи, но не читает; поскольку индекс отсутствует, чтение не будет пытаться его использовать, а это означает, что не будет никаких блокировок, но чтение может быть принудительно выполнено в дорогостоящее последовательное сканирование.

Исходя из собственного опыта, можете ли вы сказать:

  • это REINDEXINGопасно? Может ли это повредить целостность данных?
  • Может ли это занять много времени?
  • Это вероятное решение моего сценария?

Обновить:

Решение, которое работало для нас, было воссоздать тот же индекс с другим именем, а затем удалить старый индекс.

Создание индекса выполняется очень быстро, и мы уменьшили размер индекса с 650 МБ до 8 МБ. Использование COUNT(*)с betweenзанимает всего 3 секунды.

Адам Матан
источник

Ответы:

15

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

Переиндексация не должна занимать много времени, но обычно включает чтение всей таблицы, сортировку полей индекса и запись нового индекса. Учитывая время для COUNT(*)этого, вероятно, потребуется пять минут или больше.

Вряд ли это проблема индексации. COUNT(*)следует использовать сканирование таблицы, в этом случае индекс не читается. Я ожидаю, что у вас есть проблемы с IO.

Попробуйте использовать COUNT(1)или COUNT(pk_field)который может использовать индекс.

Если вы работаете на платформе Unix или Linux, вы можете отслеживать активность диска sar. У вас также может быть неисправный диск, который может значительно снизить скорость ввода-вывода.

Таблицы с большими объектами также могут значительно увеличить IO, чтобы создать записи для COUNT (*).

BillThor
источник
2
По мнению wiki.postgresql.org, COUNT(*)это лучший выбор:If you are using count(*), the database is free to use any column to count, which means it can pick the smallest covering index to scan (note that this is why count(*) is much better than count(some_field), as long as you don't care if null values of some_field are counted). Since indexes often fit entirely in memory, this means count(*) is often very fast.
orange80
1

Я не уверен в лучшем ответе для вас. Однако, эта ветка предлагает несколько хороших предложений: npostgresql.1045698.n5.nabble.com/count-performance-issue-td2067873.html

Следует отметить, что вы могли бы реализовать TRIGGER для поддержания количества строк в отдельной таблице (если ваши приложения будут часто вызывать COUNT (*)).

Некоторые ответы предполагают, что это симптоматично для базы данных, которая не была недавно очищена пылесосом (предполагается, что автоочистка отключена на вашем сервере или для этой базы данных в частности)?

Другое предложение выглядит так:

ANALYZE tablename;
SELECT reltuple FROM pg_class WHERE relname = 'tablename';

И кто-то, идентифицированный как А. Кречмер, отмечает:

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

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

Мой поиск также обнаружил WikiVS: MySQL против PostgreSQL: COUNT (*) .

Вы можете просмотреть другие результаты, которые я нашел с помощью Google: производительность postgresql count (*)

Джим Деннис
источник