Полнотекстовые запросы к этой базе данных (хранение билетов RT ( Request Tracker )) выполняются очень долго. Таблица вложений (содержащая полнотекстовые данные) составляет около 15 ГБ.
Схема базы данных выглядит следующим образом, это около 2 миллионов строк:
rt4 = # \ d + вложения
Таблица "public.attachments"
Колонка | Тип | Модификаторы | Хранение Описание
----------------- + ----------------------------- + - -------------------------------------------------- ------ + ---------- + -------------
id | целое число | notval по умолчанию nextval ('attachments_id_seq' :: regclass) | равнина |
транзакции | целое число | не нуль | равнина |
родитель | целое число | не нуль по умолчанию 0 | равнина |
MessageID | изменение характера (160) | | расширенный |
предмет | изменение характера (255) | | расширенный |
имя файла | изменение характера (255) | | расширенный |
тип контента | изменение характера (80) | | расширенный |
кодирование контента | изменение характера (80) | | расширенный |
содержание | текст | | расширенный |
заголовки | текст | | расширенный |
создатель | целое число | не нуль по умолчанию 0 | равнина |
создано | отметка времени без часового пояса | | равнина |
contentindex | цветок | | расширенный |
Индексы:
"attachments_pkey" ПЕРВИЧНЫЙ КЛЮЧ, btree (id)
"attachments1" btree (родитель)
"attachments2" btree (транзакция)
"attachments3" btree (родитель, транзакция)
"contentindex_idx" джин (contentindex)
Имеет OIDs: нет
Я могу быстро запросить базу данных (<1 с) с помощью запроса, такого как:
select objectid
from attachments
join transactions on attachments.transactionid = transactions.id
where contentindex @@ to_tsquery('frobnicate');
Однако, когда RT запускает запрос, который должен выполнить поиск по полнотекстовому индексу по той же таблице, обычно требуется сотни секунд. Результат анализа запроса выглядит следующим образом:
запрос
SELECT COUNT(DISTINCT main.id)
FROM Tickets main
JOIN Transactions Transactions_1 ON ( Transactions_1.ObjectType = 'RT::Ticket' )
AND ( Transactions_1.ObjectId = main.id )
JOIN Attachments Attachments_2 ON ( Attachments_2.TransactionId = Transactions_1.id )
WHERE (main.Status != 'deleted')
AND ( ( ( Attachments_2.ContentIndex @@ plainto_tsquery('frobnicate') ) ) )
AND (main.Type = 'ticket')
AND (main.EffectiveId = main.id);
EXPLAIN ANALYZE вывод
QUERY PLAN
-------------------------------------------------- -------------------------------------------------- -------------------------------------------------- --------------
Агрегат (стоимость = 51210.60..51210.61 строк = 1 ширина = 4) (фактическое время = 477778.806..477778.806 строк = 1 цикл = 1)
-> Вложенный цикл (стоимость = 0,00..51210.57 строк = 15 по ширине = 4) (фактическое время = 17943.986..477775.174 строк = 4197 циклов = 1)
-> Вложенный цикл (стоимость = 0.00..40643.08 строк = 6507 ширина = 8) (фактическое время = 8.526..20610.380 строк = 1714818 циклов = 1)
-> Seq Scan на основном тикете (стоимость = 0.00..9818.37 строк = 598 ширины = 8) (фактическое время = 0.008..256.042 строк = 96990 циклов = 1)
Фильтр: ((((статус) :: текст «удален» :: текст) И (id =ffectiveid) И ((тип) :: текст = «билет» :: текст))
-> Сканирование индекса с использованием транзакций1 для транзакций транзакций_1 (стоимость = 0,00..51.36 строк = 15 ширины = 8) (фактическое время = 0.102..0.202 строк = 18 циклов = 96990)
Индекс Cond: (((тип объекта) :: text = 'RT :: Ticket' :: text) AND (objectid = main.id))
-> Сканирование индекса с использованием вложений2 на вложениях вложения_2 (стоимость = 0,00..1,61 строк = 1 ширина = 4) (фактическое время = 0,266..0.266 строк = 0 циклов = 1714818)
Индекс Cond: (транзакция = транзакции_1.id)
Фильтр: (contentindex @@ plainto_tsquery ('frobnicate' :: text))
Общее время выполнения: 477778,883 мс
Насколько я могу судить, проблема заключается в том, что он не использует индекс, созданный для contentindexfield ( contentindex_idx), а выполняет фильтр для большого количества совпадающих строк в таблице вложений. Число строк в выходных данных объяснения также представляется крайне неточным, даже после недавнего ANALYZE: оценочные строки = 6507 фактических строк = 1714818.
Я не совсем уверен, куда идти дальше с этим.