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


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 lookup에 SELECT 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 열에 인덱스를 세 개의 열 조인 main과 lookup)

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.f와 product.g??? 기수의 경우 main.f와 product.g값에 1이 테이블 행의 5 % 미만에서 인덱스 main.f및 product.g정당화 될 수있다.
— RolandoMySQLDBA

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

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

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