최적화 문제 : 복합 클러스터 키, 플래그 조건 및 인덱스 병합


11

세 개의 테이블 :

product: 열 포함 : ( a, g, ...a_lot_more... )

a: PK, clustered
g: bit-column

main: 열 포함 : ( c, f, a, b, ...a_lot_more... )

c: PK, clustered
f: bit-column
(a, b): UQ 

lookup 열이있는 : ( a, b, c, i )

(a, b): PK, clustered
a: FK to product(a)
c: UQ, FK to main(c)
i: bit-column

조인에 대한 좋은 인덱스를 찾을 수 없습니다.

FROM  
    product
  JOIN 
    lookup
      ON  lookup.a = product.a  
  JOIN
    main
      ON  main.c = lookup.c 
WHERE 
      product.g = 1
  AND
      main.f = 1
  AND 
      lookup.i = 1
  AND lookup.b = 17

나는 커버링 인덱스를 시도했지만 product (g, a, ...)사용되었지만 놀라운 결과는 아닙니다.

lookup테이블 의 일부 인덱스 조합은 이전 계획에 비해 약간의 효율성 향상과 함께 인덱스 병합으로 실행 계획을 생성합니다.

내가 놓친 명백한 조합이 있습니까?

구조의 재 설계가 도움이 될 수 있습니까?

DBMS는 MySQL 5.5이며 모든 테이블은 InnoDB를 사용하고 있습니다.


테이블 크기 :

product: 67K   ,  g applied:    64K 

main:   420K   ,  f applied:   190K

lookup:  12M   ,  b,i applied:  67K 

필터 술어를 조인으로 이동하고 옵티마이 저가 적절한 것으로 수행되는지 확인하십시오. SQL Server의 옵티마이 저가 이전에 실패한 것을 보았습니다.
ConcernedOfTunbridgeWells

제품 테이블에 참여하는 것이 없기 때문에 데카르트 제품처럼 보입니다. 아니면 뭔가를 그리워 했습니까 ???
RolandoMySQLDBA

@RolandoMySQLDBA : 네 말이 맞아. 쿼리를 수정하겠습니다.
ypercubeᵀᴹ

답변:


3

이것은 나를 아프게합니다 ...

전에 InnoDB와 함께 임시 테이블을 사용해야했습니다. 필터를 사용하여로드하고 인덱스를 작성하고 이러한 임시 테이블을 결합하십시오.

내가 생각하는 문제는 InnoDB에 Nested Join 알고리즘 만있는 경우입니다. 어른이 된 RDBMS 쿼리 최적화 프로그램이 더 많이 사용해야합니다. 이는 InnoDB에서 데이터웨어 하우스 유형로드를 실행하려는 시도를 기반으로합니다.

임시 테이블은 전체적으로 복잡성을 MySQL 쿼리 최적화 프로그램 수준으로 끌어 놓습니다.


Thnx, 시도하겠습니다. 수 또는 행 (기준이 적용된 후 각각 64K, 67K, 190K는 크지 않음). 어쩌면 나는 main데이터를 비정규 화 하여 세 테이블 중 하나를 제거하려고 시도해야 lookup합니까?
ypercubeᵀᴹ

1
@ypercube : 하부 페이지 밀도는 다른 문제 = 행이 더 넓은 것 denormalising
GBN

3

카티 전 곱처럼 보입니다. 가입 기준 다시 실행

FROM  
    product
  JOIN 
    lookup
      ON  product.a = lookup.a  
  JOIN
    main
      ON  main.c = lookup.c 
WHERE 
      product.g = 1
  AND
      main.f = 1
  AND 
      lookup.i = 1
  AND lookup.b = 17

대체 제안

이것은 정통처럼 보이지 않고 SQL Anitpattern과 같은 냄새가 날 수 있지만 여기에 있습니다 ...

FROM  
    product
JOIN 
    (
        SELECT * FROM lookup
        WHERE i=1 AND b=17
    ) lookup ON product.a = lookup.a  
JOIN
   main ON main.c = lookup.c 
WHERE 
    product.g = 1 AND main.f = 1

나는 움직이지 않았다 product.g = 1그리고 main.f = 1그들이 비트 필드이며, 단지 지점에 테이블 스캔을 할 것 때문에 서브 쿼리. 비트 필드가 인덱스 인 경우에도 Query Optimizer는 해당 인덱스를 무시합니다.

물론, 당신은 변경할 수 SELECT * FROM lookupSELECT a FROM lookup에서 당신의 선택이 필요로하지 않는 경우 아무것도lookup

아마도 룩업과 메인 사이의 JOIN에 a, b가 포함될 수 있습니다.

FROM  
    product
  JOIN 
    lookup
      ON  product.a = lookup.a  
  JOIN
    main
      ON  main.a = lookup.a AND main.b = lookup.b
WHERE 
      product.g = 1
  AND
      main.f = 1
  AND 
      lookup.i = 1
  AND lookup.b = 17

또는 다시 C를 넣어 (의 3 열에 인덱스를 세 개의 열 조인 mainlookup)

FROM  
    product
  JOIN 
    lookup
      ON  product.a = lookup.a  
  JOIN
    main
      ON main.a = lookup.a
      AND main.b = lookup.b
      AND main.c = lookup.c
WHERE 
      product.g = 1
  AND
      main.f = 1
  AND 
      lookup.i = 1
  AND lookup.b = 17

Thnx. EXPLAIN 계획은 다르지만 성능은 비슷합니다.
ypercubeᵀᴹ

무엇의 기수 main.fproduct.g??? 기수의 경우 main.fproduct.g값에 1이 테이블 행의 5 % 미만에서 인덱스 main.fproduct.g정당화 될 수있다.
RolandoMySQLDBA

걱정하지 마십시오. 이미 색인이 생성되었습니다. 의 카디널리티가있는 경우 main.fproduct.g2, 당신은 그 인덱스를 도랑 수 있습니다.
RolandoMySQLDBA

사용 된 테이블 크기 및 행을 사용하여 질문을 편집했습니다 (조건이 적용된 후).
ypercubeᵀᴹ

나는 c 대신 a, b에 참여하는 제안을 제안했다. 이것이 다른 EXPLAIN 계획을 세우는 지
확인해보십시오
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.