优化问题:复合集群键,标志条件和索引合并


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

看起来像笛卡尔积,因为在积表中看不到任何JOINING。还是我错过了什么?
RolandoMySQLDBA'8年

@RolandoMySQLDBA:你是对的。我将更正查询。
ypercubeᵀᴹ

Answers:


3

这让我很痛苦

我以前不得不在InnoDB中使用临时表。用过滤器加载它们,创建索引,加入这些临时表。

我认为问题在于InnoDB是否只有嵌套连接算法:成熟的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 = 1and main.f = 1移到子查询中,因为它们是位字段,将只在此时进行表扫描。即使位字段是索引,查询优化器也会简单地忽略这样的索引。

当然,你可以改变SELECT * FROM lookup,以SELECT a FROM lookup从,如果你的SELECT并不需要什么lookup

如果这有意义的话,也许在查找和main之间的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和上三列联接(指数在三列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

谢谢 EXPLAIN计划不同,但性能相似。
ypercubeᵀᴹ

什么的基数main.fproduct.g??? 如果的基数main.fproduct.g为值1是表中的行的不足5%,在一个索引main.fproduct.g可以是合理的。
RolandoMySQLDBA

没关系,它们已经被索引了。如果基数main.fproduct.g是2,你可以抛弃这些索引。
RolandoMySQLDBA

使用表大小和使用的行(在应用条件之后)编辑了问题。
ypercubeᵀᴹ

我更新了我的问题,建议加入a,b而不是c。看看是否制定了不同的EXPLAIN计划
RolandoMySQLDBA 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.