Optimizasyon sorunu: bileşik kümelenmiş anahtarlar, işaret koşulları ve dizin birleştirme


11

Üç tablo:

product: sütunlarla: ( a, g, ...a_lot_more... )

a: PK, clustered
g: bit-column

main: sütunlarla: ( c, f, a, b, ...a_lot_more... )

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

lookup sütunlarla: ( a, b, c, i )

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

Katılmak için iyi dizinler bulamıyorum:

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

Bir kaplama endeksi denedim product (g, a, ...)ve kullanılır ama muhteşem sonuçlarla değil.

lookupTablodaki bazı endeks kombinasyonları , bir önceki plana göre hafif verimlilik kazancı ile endeks birleştirme ile yürütme planları üretmektedir.

Kaçırdığım açık bir kombinasyon var mı?

Yapının yeniden tasarımı yardımcı olabilir mi?

DBMS MySQL 5.5 ve tüm tablolar InnoDB kullanıyor.


Tablo boyutları:

product: 67K   ,  g applied:    64K 

main:   420K   ,  f applied:   190K

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

Filtre tahminlerini birleştirme noktalarına taşımayı deneyin ve optimize edicinin bununla mantıklı bir şey yapıp yapmadığını görün. SQL Server'ın optimize edicisinin daha önce başarısız olduğunu gördüm.
ConcernedOfTunbridgeWells

Kartezyen bir ürüne benziyor çünkü ürün tablosundan KATILAN bir şey görmüyorum. Yoksa bir şey mi kaçırdım ???
RolandoMySQLDBA

@RolandoMySQLDBA: Haklısın. Sorguyu düzeltirim.
ypercubeᵀᴹ

Yanıtlar:


3

Bu beni acıtıyor ...

Daha önce InnoDB ile geçici tabloları kullanmak zorunda kaldım. Bunları filtrelerle yükleyin, bir dizin oluşturun, bu geçici tabloya katılın.

Ben hesap olarak sorun InnoDB sadece Yuvalanmış birleştirme algoritması varsa: yetişkin RDBMS sorgu optimisers kullanmak için daha var. Bu, InnoDB'de Veri Ambarı türü yükleri çalıştırmaya çalışmayı temel alır.

Geçici tablolar genel karmaşıklığı MySQL sorgu optimizer'ın seviyesine sürükler ...


Teşekkürler, bunu deneyeceğim. Sayı veya satırlar (ölçütler uygulandıktan sonra sırasıyla büyük, 64K, 67K, 190K değildir). Belki mainveriyi denormalize ederek üç tablodan ( ) kurtulmaya çalışmalıyım lookup?
ypercubeᵀᴹ

1
@ ypercube: denormalising satırları genişletir, sayfa yoğunluğunu
azaltır

3

Kartezyen bir ürüne benziyor. KATILMA Kriterlerini Yeniden Yap

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

ALTERNATİF ÖNERİ

Bu alışılmadık gibi görünebilir ve muhtemelen SQL Anitpattern gibi kokuyor, ama işte gidiyor ...

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

Ben alt alanları olduğundan ve sadece bir tablo tarama yapacağız çünkü product.g = 1ve main.f = 1alt sorgulara hareket etmedi . Bit alanları dizin olsa bile, Sorgu Optimize Edici böyle bir dizini yok sayar.

Tabii ki, değişebilir SELECT * FROM lookupiçin SELECT a FROM lookupadresinin SEÇ ihtiyacı yoksa bir şeylookup

Belki de mantıklıysa, arama ve ana arasındaki birleşimde a, b'yi dahil edin

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

veya arka c koymak ve (içinde üç sütun üzerine Index üç sütun üzerine katılmak mainve 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. Farklı EXPLAIN planı, ancak benzer performans.
ypercubeᵀᴹ

Ne kardinalitesi main.fve product.g??? Kardinalitesi ise main.fve product.gdeğeri 1 Tablo sıralarının% 5'ten az, bir endekstir main.fve product.ghaklı olabilir.
RolandoMySQLDBA

Boş ver, zaten endeksli. Kardinalitesi Eğer main.fve product.g2 ise, o endeksler Suya da inebiliriz.
RolandoMySQLDBA

Soruyu, kullanılan tablo boyutları ve satırlarla (koşullar uygulandıktan sonra) düzenledi.
ypercubeᵀᴹ

Sorumu güncelledim, öneri c yerine a, b'ye katılmak. Bunun farklı bir EXPLAIN planı yapıp yapmadığını görün
RolandoMySQLDBA
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.