PostgreSQL 9.6에서 원하지 않는 Nest 루프와 해시 조인


13

PostgreSQL 9.6 쿼리 계획에 문제가 있습니다. 내 쿼리는 다음과 같습니다

SET role plain_user;

SELECT properties.*
FROM properties
JOIN entries_properties
  ON properties.id = entries_properties.property_id
JOIN structures
  ON structures.id = entries_properties.entry_id 
WHERE structures."STRUKTURBERICHT" != ''
  AND properties."COMPOSITION" LIKE 'Mo%'
  AND (
    properties."NAME" LIKE '%VASP-ase-preopt%'
    OR properties."CALCULATOR_ID" IN (7,22,25)
  )
AND properties."TYPE_ID" IN (6)

위의 테이블에 대해 행 수준 보안을 사용하도록 설정했습니다.

나는 한 VACUUM ANALYZE쿼리를 실행하기 전에, 그러나 그것은 도움이되지 않았다.

set enable_nestloop = False계획을 세우는 것이 좋지 않으며 계획자에게 다른 유사한 옵션 이 있다는 것을 알고 있습니다. 그러나 중첩 루프를 비활성화하지 않고 플래너가 어떻게 해시 조인을 사용하도록 "설득"할 수 있습니까?

쿼리를 다시 작성하는 것은 옵션입니다.

RLS를 우회하는 역할로 동일한 쿼리를 실행하면 매우 빠르게 실행됩니다. 행 수준 보안 정책은 다음과 같습니다.

CREATE POLICY properties_select
ON properties
FOR SELECT
USING (
  (
    properties.ouid = get_current_user_id()
    AND properties.ur
  )
  OR (
    properties.ogid in (select get_current_groups_id())
    AND properties.gr
  )
  OR properties.ar
);

어떤 아이디어 나 제안이라도 대단히 감사하겠습니다.


그냥 조금 혼란 : 왜해야 AND properties."TYPE_ID" IN (6);하지 = 6;?
Vérace

2
@ Vérace = =가 더 현명하게 사용되면 둘 다 같은 방식으로 계획됩니다. 내 가정은 그가 하나 이상의 가치를 가지고 놀거나 ORM이 다소 게으른 것이라고 가정합니다.
Evan Carroll

답변:


15

여기서 일어나는 일은 Nested Loop가 한쪽에 떨어져 있다는 것입니다. 중첩 루프 는 한 행을 반환하는 것과 같이 한쪽이 매우 작을 때 실제로 잘 작동 합니다. 쿼리에서 플래너가 여기에서 비틀 거리고 해시 조인이 한 행만 반환한다고 추정합니다. 대신 해시 조인 (property_id = id)은 1,338 개의 행을 반환합니다. 이렇게하면 1,338 개의 루프가 이미 3,444 개의 행이있는 중첩 루프의 다른 쪽에서 실행됩니다. 그것은 오직 하나만 기대할 때 (하위 루프가 아닌) 헬라-로트입니다. 어쨌든 ..

우리가 아래로 내려갈 때의 추가 조사는 해시 조인이 이것으로부터 발생하는 추정에 의해 실제로 붕괴되었음을 보여줍니다.

Filter: (((properties."COMPOSITION")::text ~~ 'Mo%'::text) AND (((properties."NAME")::text ~~ '%VASP-ase-preopt%'::text) OR (properties."CALCULATOR_ID" = ANY ('{7,22,25}'::integer[]))))

PostgreSQL은 한 행을 반환 할 것으로 예상합니다. 그러나 그렇지 않습니다. 그리고 그것은 정말로 당신의 문제입니다. 여기 썰매 망치를 꺼내거나 사용하지 않는 몇 가지 옵션이 있습니다.nested_loop

  • propertiesseq 스캔을 완전히 건너 뛰거나 리턴을 더 잘 추정 할 수 있도록 인덱스를 하나 또는 두 개 추가 할 수 있습니다 .

    CREATE INDEX ON properties USING ( "TYPE_ID", "CALCULATOR_ID" );
    -- the gist_trgm_ops may or may not be needed depending on selectivity of above.
    CREATE INDEX ON properties USING GIST (
      "COMPOSITION" gist_trgm_ops,
      "NAME"        gist_trgm_ops
    );
    ANALYZE properties;
  • 또는 OFFSET 0펜스를 생성하는 CTE 또는 하위 선택으로 속성 항목을 이동할 수 있습니다 .

    WITH t AS (
      SELECT *
      FROM properties.
      WHERE "COMPOSITION" LIKE 'Mo%'
      AND (
        "NAME" LIKE '%VASP-ase-preopt%'
        OR "CALCULATOR_ID" IN (7,22,25)
      )
      AND "TYPE_ID" IN (6)
    )
    SELECT * FROM structures
    JOIN t ON (
      structures.id = entries_properties.entry_id
    )
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.