2016-08-02 1 views
0

**** 편집 ****'IN'쿼리를 어떻게 최적화 할 수 있습니까?

14ms는 "PostgresSQL Explain"에서 아래에서 볼 수 있듯이 많이 보이지 않을 수 있습니다. PostgreSQL은 80,000 행의 연속 스캔을 수행합니다. 이 검사를 피하고 대신 색인 조회를 수행하는 방법이 있어야합니다.

**** 편집 END ****

내가 스키마의 아이디어로 주위를 연주하고 있는데이 세 개의 테이블 다음 한 : 테이블은 10 만 개 무작위 항목으로 채워집니다

합니다. index_username_email(key)

내 SQL 쿼리에 고유하지 않은 인덱스

entities(_primary_key SERIAL PRIMARY KEY, _id CHAR(32) UNIQUE, 
    data BYTEA) 

index_username_profile_names(_id CHARE(32) PRIMARY KEY, 
    key VARCHAR UNIQUE) 

index_username_email(_id CHAR(32) PRIMARY KEY, key VARCHAR) 

는 '테스트'하지 종료는하지만

SELECT data FROM entities WHERE 
    _id IN (SELECT _id FROM index_users_email WHERE key = 'test') 
OR 
    _id in (SELECT _id FROM index_users_profile_name WHERE key = 'test') 

이것은 '인덱스 중 하나를 후후 14ms 소요 '테이블, 내가 PostgreSQL이나 MySQL을 사용하든 상관없이, 내가 잘못하고있는 것이 틀림 없다.

내가 어떻게 최적화 할 수 있는지 또는 내가 잘못하고있는 것을 아는가?

감사합니다.

포스트 그레스 설명 : 하나의 잠재적 인 대답은 unionjoin처럼

Seq Scan on entities (cost=16.88..4776.15 rows=80414 width=163) (actual time=15.169..15.169 rows=0 loops=1) 
    Filter: ((hashed SubPlan 1) OR (hashed SubPlan 2)) 
    Rows Removed by Filter: 107218 
    SubPlan 1 
    -> Index Scan using index_users_email_key_idx1 on index_users_email (cost=0.42..8.44 rows=1 width=33) (actual time=0.039..0.039 rows=0 loops=1) 
      Index Cond: ((key)::text = 'test'::text) 
    SubPlan 2 
    -> Index Scan using index_users_profile_name_key_idx1 on index_users_profile_name (cost=0.42..8.44 rows=1 width=33) (actual time=0.071..0.071 rows=0 loops=1) 
      Index Cond: ((key)::text = 'test'::text) 
Planning time: 0.202 ms 
Execution time: 15.216 ms 
+4

14 * 밀리 초 * "무려"아니다. –

+0

1ms보다 작을 때는 다음과 같습니다. D –

+0

아무 것도 작지 않습니다. 8ms – Drew

답변

1

OR 에디션 (join-) 조건은 일반적으로 나쁜 대신 UNION을 시도 :

SELECT data FROM entities 
WHERE _id IN 
(SELECT _id 
    FROM index_users_email 
    WHERE key = 'test' 
) 
UNION 
SELECT data FROM entities 
WHERE _id in 
(SELECT _id 
    FROM index_users_profile_name 
    WHERE key = 'test' 
) 
+0

Yeap. UNION이 그랬다. 나는 또한 "IN"을 JOIN으로 바꿨고 매력처럼 작동합니다. –

+0

다시 감사드립니다. D –

0
SELECT data 
FROM entities e 
    LEFT OUTER JOIN index_users_email iue ON e._id=iue._id and iue.key = 'test' 
    LEFT OUTER JOIN index_users_profile_name iupn ON e._id=iupn._id and iupn .key = 'test' 
WHERE 
    iue._id IS NOT NULL or iupn._id IS NOT NULL 
+0

트릭을 수행하지 않는 것 같습니다. 40ms –

+0

이 코드가 문제를 해결하는 데 도움이 될 수 있지만 _why_ 및/또는 _how_에 관한 추가 컨텍스트를 제공하면 에 응답하면 장기적인 가치가 크게 향상됩니다. 제한 사항 및 가정 사항을 포함하여 설명을 추가하려면 답변을 [편집하십시오. –

0

가 보이는 :

explain select data from entities as t join (select _id from index_users_email where key = 'test' union select _id from index_users_profile_name where key = 'test') u on t._id = u._id; 
                   QUERY PLAN                 
------------------------------------------------------------------------------------------------------------------------------------------- 
Nested Loop (cost=17.32..33.82 rows=2 width=163) 
    -> Unique (cost=16.90..16.91 rows=2 width=33) 
     -> Sort (cost=16.90..16.91 rows=2 width=33) 
       Sort Key: index_users_email._id 
       -> Append (cost=0.42..16.89 rows=2 width=33) 
        -> Index Scan using index_users_email_key_idx1 on index_users_email (cost=0.42..8.44 rows=1 width=33) 
          Index Cond: ((key)::text = 'test'::text) 
        -> Index Scan using index_users_profile_name_key_idx1 on index_users_profile_name (cost=0.42..8.44 rows=1 width=33) 
          Index Cond: ((key)::text = 'test'::text) 
    -> Index Scan using entities__id_key on entities t (cost=0.42..8.44 rows=1 width=196) 
     Index Cond: (_id = index_users_email._id) 
(11 rows) 

Time: 0.714 ms 
+1

'explain '대신'explain analyze'를 사용하십시오. – joop

0

는 해당 테이블의 기본 키의 활용으로이 더 나은 성능을해야합니다 :

select data 
from entities 
where 
    exists (
     select _id 
     from index_users_email 
     where key = 'test' and _id = entities._id 
    ) or exists (
     select _id 
     from index_users_profile_name 
     where key = 'test' and _id = entities._id 
    ) 
+0

16ms가 걸립니다. 당신이 언급 한대로 모든 키를 사용하지만 엔티티에 대한 seq 스캔은 ... "엔티티에 대한 Seq 스캔 (비용 = 0.00..955782.93 행 = 80414 너비 = 163) (실제 시간 = 15.524..15.524 행 = 0 루프 = 1) " –

1

14 밀리 초는 꽤 괜찮습니다. 쿼리가 밀리 초 미만으로 실행되어야한다고 생각하는 이유를 모르겠습니다. 쿼리를 설정하고, 데이터가 메모리에 있는지 확인하고, 인덱스가 어디에 있는지 식별하는 등의 작업이 많이 있습니다. 대부분의 질의에 대해, 이것은 사소한 것입니다. 그러나 쉽게 밀리 세컨드까지 추가 할 수 있습니다. (우리가 그들을 사용할 때)

  • 컴퓨터를 결정하지 않은 : 당신이 진짜 타이밍을하고 있다면

    둘째, 마음에 다음과 같은 유지. 타이밍을 여러 번 실행해야합니다. 밀리 세컨드가 걸리면 보통 안정된 판독 값을 얻으려면 수천 번이됩니다.

  • 각 타이밍마다 동일한 상태로 시스템을 초기화하십시오. 콜드 캐시 또는 웜 캐시를 원할지 결정해야하지만 타이밍은 모두 동일한 시스템에 있어야합니다.
  • 다른 작업에서 시스템을 분리하십시오. 백그라운드 작업 (마우스 이동도 포함)은 성능에 영향을 줄 수 있습니다.쿼리의 측면에서

는, 내가 생각할 수있는 한 가지 =exists을 사용하는 것입니다

SELECT e.data 
FROM entities e 
WHERE _id = (SELECT _id FROM index_users_email WHERE key = 'test') OR 
     EXISTS (SELECT 1 FROM index_users_profile_name iupn WHERE iupn._id = e.id AND iupn.key = 'test'); 

기껏해야하지만, 나는 떨어져 밀리 초 또는 두 개의 면도 것이 이러한 추측하고있어 쿼리.

+0

Postgres Explain을 살펴보십시오. Seq Scan에 대한 이유는 없습니다. 또한 0.5ms가 소요되는 쿼리의 경우 14ms가 큰 저하입니다. –

+0

관련 통계의 seqscan : abscense에는 충분한 이유가 있습니다. – wildplasser

관련 문제