Какой столбец должен быть проиндексирован?
У меня есть следующий запрос, который будет попадать в базу данных каждую минуту
SELECT n.notificationid ,n.notificationtype FROM notification n INNER JOIN usernotification un ON n.notificationid = un.notificationid LEFT JOIN vhctotal vt ON vt.vhcid = n.vhcid WHERE CASE WHEN n.notificationtype = 2 THEN n.datechecked = '' ELSE to_timestamp(n.datechecked, 'DD/MM/YYYY hh24:mi:ss') > NOW() - INTERVAL '30 days' END AND date_trunc('day', n.vhcdate::TIMESTAMP) = CURRENT_DATE AND un.commentstatus = 0 AND un.userid = 30427 OR ( un.commentstatus = 1 AND un.updateddatetime > current_timestamp - interval '5 minutes' )
Вышеприведенный запрос занимает немного много времени для выполнения. когда я проверяю эти таблицы, индексация не выполняется должным образом.
Я хотел бы создать индексы для этих таблиц. Должен ли я создавать индекс для столбцов, которые используются в предложении WHERE? Дает ли это лучшую производительность ? Пожалуйста, предложите .
Что я уже пробовал:
ПЛАН ЗАПРОСА
Nested Loop Left Join (cost=25.96..2136.39 rows=1 width=237) (actual time=49.911..49.911 rows=0 loops=1) Join Filter: (vt.vhcid = n.vhcid) -> Hash Join (cost=25.96..2089.81 rows=1 width=163) (actual time=49.908..49.908 rows=0 loops=1) Hash Cond: (un.notificationid = n.notificationid) Join Filter: ((CASE WHEN ((n.notificationtype)::text = '2'::text) THEN ((n.datechecked)::text = ''::text) ELSE (to_timestamp((n.datechecked)::text, 'DD/MM/YYYY hh24:mi:ss'::text) > (now() - '30 days'::interval)) END AND (date_trunc('day'::text, (n.vhcdate)::timestamp without time zone) = ('now'::cstring)::date) AND (un.commentstatus = 0) AND (un.userid = 30427)) OR ((un.commentstatus = 1) AND (un.updateddatetime > (now() - '00:05:00'::interval)))) Rows Removed by Join Filter: 26406 -> Seq Scan on usernotification un (cost=0.00..528.36 rows=26136 width=36) (actual time=0.009..3.937 rows=26406 loops=1) -> Hash (cost=18.76..18.76 rows=576 width=127) (actual time=0.420..0.420 rows=577 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 96kB -> Seq Scan on notification n (cost=0.00..18.76 rows=576 width=127) (actual time=0.004..0.105 rows=577 loops=1) -> Seq Scan on vhctotal vt (cost=0.00..33.48 rows=1048 width=74) (never executed) Total runtime: 50.033 ms
Manoj Kumar Choubey
Я не могу дать вам идеальный ответ без вашей структуры базы данных, но первое, что вам нужно сделать, это проверить, что ваша база данных нормализована и создать первичные ключи и / или внешние ключи по мере необходимости, например, "notificationid" может быть первичным ключом вашей таблицы.
во-вторых, вы пробуете какой-то план запроса, попробуйте сделать это в query profiler и query analyzer.
Richard Deeming
to_timestamp(n.datechecked, 'DD/MM/YYYY hh24:mi:ss')
Храните ли Вы значения даты и времени в строковом столбце? Если так, то это очевидная вещь, которую нужно исправить.
date_trunc('day', n.vhcdate::TIMESTAMP) = CURRENT_DATE
Как правило, следует избегать выполнения вычислений по столбцам таблицы в
WHERE
предложение, так как оно не позволит вашему запросу использовать индекс в этом столбце. Вместо того чтобы усекать время и сравнивать результат с датой, проверьте, является ли столбец больше или равен дате и меньше одного дня после даты:AND n.vhcdate >= CURRENT_DATE AND n.vhcdate < CURRENT_DATE + INTERVAL '1 day'
King Fisher
вот у ее был написан такой,
King Fisher
спасибо , но эта колонка была создана как varchar , я не могу использовать это условие AND n.vhcdate >= CURRENT_DATE AND n.vhcdate < CURRENT_DATE + INTERVAL '1 day'
, Он показывает " оператор не существует: переменный символ = дата"
Richard Deeming
Ну, вот и очевидное место для начала! :)
Вы должны никогда храните даты в виде строк. Вместо этого всегда используйте один из доступных типов даты и времени.
Это не только ускорит ваши запросы, но и предотвратит хранение недопустимых или неоднозначных данных в столбце.