PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Warum führt die Verwendung desselben Felds beim Filtern zu unterschiedlichen Ausführungszeiten? (andere Indexnutzung)

Als Problemumgehung können wir zusätzlich SELECT ein Alias ​​für die Spalte, die bei PARTITION BY verwendet wird Ausdruck. Dann wendet PG die Optimierung an und verwendet den Index.

Die Antwort auf die Frage könnte lauten:PG wendet keine Optimierung an, wenn zusammengesetzter Typ verwendet wird . Beachten Sie, wie es funktioniert:

PARTITION | FILTER | IS USED?
------------------------------
ALIAS     | ORIG   | NO
ALIAS     | ALIAS  | YES
ORIG      | ALIAS  | NO
ORIG      | ORIG   | NO

Siehe diese dbfiddle

create table agreement ( ag_id int, name text, cost numeric(10,2) );
create index ag_idx on agreement (ag_id);
insert into agreement (ag_id, name, cost) values ( 1, '333', 22 ),
(1,'333', 33), (1, '333', 7), (2, '555', 18 ), (2, '555', 2), (3, '777', 4);
select * from agreement;

create function initial () 
returns table( agreement_id int, ag agreement ) language sql stable AS $$
select ag_id, t from agreement t;
$$;
select * from initial() t;

explain( analyze, costs, buffers, verbose ) with totals_by_ag as (
  select 
    *,
    sum( (t.ag).cost ) over ( partition by agreement_id ) as total
  from initial() t
)
select * from totals_by_ag t
where (t.ag).ag_id = 1; -- index is NOT USED

explain( analyze, costs, buffers, verbose ) with totals_by_ag as (
  select 
    *,
    sum( (t.ag).cost ) over ( partition by agreement_id ) as total
  from initial() t
)
select * from totals_by_ag t
where agreement_id = 1; -- index is used when alias for column is used

explain( analyze, costs, buffers, verbose ) with totals_by_ag as (
  select 
    *,
    sum( (t.ag).cost ) over ( partition by (t.ag).ag_id ) as total --renamed
  from initial() t
)
select * from totals_by_ag t
where agreement_id = 1; -- index is NOT USED because grouping by original column

explain( analyze, costs, buffers, verbose ) with totals_by_ag as (
  select 
    *,
    sum( (t.ag).cost ) over ( partition by (t.ag).ag_id ) as total --renamed
  from initial() t
)
select * from totals_by_ag t
where (t.ag).ag_id = 1; -- index is NOT USED even if at both cases original column