Кто-нибудь когда-нибудь сталкивался с этим? Postgres Enterprise DB Advanced Server 11.5.12
sysdate()
(Oracle проприетарный) приводит к сканированию Seq, в данном случае 4782 строк:
EXPLAIN SELECT p.id, p.practice
FROM PatientStatistics ps
INNER JOIN Patients p
ON p.id=ps.patient
WHERE ps.nextfutureapptdateservertime <= sysdate()
ORDER BY p.id ASC;
Hash Join (cost=799.81..1761.53 rows=4782 width=8)
Hash Cond: (p.id = ps.patient)
-> Index Only Scan using patients_index3 on patients p (cost=0.29..921.44 rows=15442 width=8)
-> Hash (cost=644.11..644.11 rows=4782 width=4)
-> Seq Scan on patientstatistics ps (cost=0.00..644.11 rows=4782 width=4)
Filter: (nextfutureapptdateservertime <= sysdate)
Изменение на now()
или current_timestamp
(SQL Standard) устраняет проблему. Postgres правильно использует индекс:
EXPLAIN SELECT p.id, p.practice
FROM PatientStatistics ps
INNER JOIN Patients p
ON p.id=ps.patient
WHERE ps.nextfutureapptdateservertime <= now()
ORDER BY p.id ASC;
Nested Loop (cost=0.57..51.41 rows=17 width=8)
-> Index Only Scan using "patientstatisti_idx$$_0c9a0048" on patientstatistics ps (cost=0.29..8.53 rows=17 width=4)
Index Cond: (nextfutureapptdateservertime <= now())
-> Index Scan using patients_pk on patients p (cost=0.29..2.52 rows=1 width=8)
Index Cond: (id = ps.patient)
Интересно отметить различия в выводе этих функций:
SELECT now();
SELECT current_timestamp;
15-JAN-20 09:36:41.932741 -05:00
15-JAN-20 09:36:41.932930 -05:00
SELECT sysdate();
15-JAN-20 09:37:17
Возможно, индексы даты Postgres хешируются с использованием Datetime которые имеют десятичную часть. Планировщик видит, что ему была передана дата без десятичного числа, и он знает, что ключи индекса не будут точно выровнены, поэтому он возвращается к сканированию, чтобы убедиться, что запрос дает 100% точные результаты.
Я не смог ничего найти об этом онлайн после 30-минутного поиска в Google.