Postgresql - стратегия индексации поля даты в столбце jsonb - PullRequest
0 голосов
/ 18 июня 2020

Есть ли лучший способ работы с полями даты в столбцах jsonb? В следующем сценарии я пытаюсь найти «Пациентов» по ​​дате их рождения.

SELECT P.resource ->> 'id' ID, P.resource -> 'birthDate' DoB, CONCAT(P.resource -> 'name' -> 0 -> 'given', ' ', P.resource -> 'name' -> 0 -> 'family') "name"
FROM recorditems P
WHERE  P.resource ->> 'resourceType' = 'Patient'
    AND (P.resource ->> 'birthDate')::date BETWEEN '1975-01-01'::date AND '1995-01-01'::date;

Индекс джина может пригодиться для первого предиката, если я перепишу его с помощью оператора @>. Есть ли предложения по индексу для второго предиката? Разве преобразование строки в текущую не будет накладными расходами на производительность?

explain analyze говорит следующее:

 Gather  (cost=1000.00..229569.96 rows=39 width=96) (actual time=6.178..1205.812 rows=699 loops=1)
   Workers Planned: 2
   Workers Launched: 2
   ->  Parallel Seq Scan on recorditems p  (cost=0.00..228566.06 rows=16 width=96) (actual time=13.747..1172.495 rows=233 loops=3)
         Filter: (((resource ->> 'resourceType'::text) = 'Patient'::text) AND (((resource ->> 'birthDate'::text))::date >= '1975-01-01'::date)
AND (((resource ->> 'birthDate'::text))::date <= '1995-01-01'::date))
         Rows Removed by Filter: 524492
 Planning Time: 0.068 ms
 JIT:
   Functions: 12
   Options: Inlining false, Optimization false, Expressions true, Deforming true
   Timing: Generation 2.296 ms, Inlining 0.000 ms, Optimization 0.891 ms, Emission 16.132 ms, Total 19.320 ms
 Execution Time: 1206.889 ms
(12 rows)

Time: 1207.337 ms (00:01.207)

1 Ответ

2 голосов
/ 18 июня 2020

Идеальный индекс для этого запроса был бы:

CREATE INDEX ON recorditems (
   (resource ->> 'resourceType'),
   ((resource ->> 'birthDate')::date)
);

Это не работает, потому что приведение от text к date не IMMUTABLE (попробуйте SELECT 'today'::date;).

Если вы знаете, что хранятся только даты ISO, вы можете обойти это с помощью специальной функции:

CREATE FUNCTION text_to_date(text) RETURNS date
   IMMUTABLE LANGUAGE sql AS
'SELECT CAST($1 AS date)';

Затем вы должны использовать эту функцию в своем запросе и индексе:

CREATE INDEX ON recorditems (
   (resource ->> 'resourceType'),
   (text_to_date(resource ->> 'birthDate'))
);
...