性能:MySQL中的OR条件会显着降低内部连接速度吗?

时间:2016-01-12 10:28:30

标签: mysql performance hibernate entity-attribute-value

我在使用连接执行复杂查询时遇到了很多困难。

简而言之,我有一个表个人资料以及一个详细信息表 ProfileEntries 。配置文件条目组成路径/值对(确实更复杂,因为我可以有字符串条目和数字条目,但我认为这不是性能问题的根源)。我想找到某些条目匹配的所有配置文件。

list of list of uint

(抱歉,为了保密,我不得不对字符串值进行匿名处理)。这个查询是由Hibernate生成的(即使有一些更多的连接,但我简化了查询以便于分析)。如果我针对SQLServer或HSQL运行它,它就像闪电一样快,如果我对MySQL运行它就会很慢。 我已经在所有相关列上定义了索引,特别是在'path'列上,这是最具判别力的索引。 MySQL应该能够使用这些索引来优化访问。

select distinct profile0_.id as id1_7_ 
from SCONProfile profile0_ 
inner join SCONProfileEntry profileent1_ on profile0_.id=profileent1_.profile_id 
inner join SCONProfileEntry profileent2_ on profile0_.id=profileent2_.profile_id 
inner join SCONProfileEntry profileent3_ on profile0_.id=profileent3_.profile_id 
inner join SCONProfileEntry profileent4_ on profile0_.id=profileent4_.profile_id 
inner join SCONProfileEntry profileent5_ on profile0_.id=profileent5_.profile_id 
inner join SCONProfileEntry profileent6_ on profile0_.id=profileent6_.profile_id 
inner join SCONProfileEntry profileent7_ on profile0_.id=profileent7_.profile_id 
inner join SCONProfileEntry profileent8_ on profile0_.id=profileent8_.profile_id 
inner join SCONProfileEntry profileent9_ on profile0_.id=profileent9_.profile_id 
inner join SCONProfileEntry profileent10_ on profile0_.id=profileent10_.profile_id 
inner join SCONProfileEntry profileent11_ on profile0_.id=profileent11_.profile_id 

where (profileent11_.path='AAAAAA/DDDD/Deutsch' and profileent11_.numericalValue=1 or profileent11_.path='AAAAAA/DDDD/Englisch' and profileent11_.numericalValue=1) 
and (profileent10_.path='AAAAAA/WWWWW/EEE' and profileent10_.numericalValue=1 or profileent10_.path='AAAAAA/WWWWW/UUU' and profileent10_.numericalValue=1) 
and profileent9_.path='AAAAAA/RRRR/WWWWW' and (profileent9_.value='Nicht notwendig' or profileent9_.value='SSSS vor Ort beteiligt' or profileent9_.value='zust. LLLL beteiligt') 
and (profileent8_.path='AAAAAA/RRRR/DDDDRRRR' and profileent8_.numericalValue=1 or profileent8_.path='AAAAAA/RRRR/RRRR-RRRR' and profileent8_.numericalValue=1 or profileent8_.path='AAAAAA/RRRR/R2RRR-RRRR' and profileent8_.numericalValue=1 or profileent8_.path='AAAAAA/RRRR/IIIII' and profileent8_.numericalValue=1)
and (profileent7_.path='UUUUUUUU/KKKKKK/DDDDD' and profileent7_.numericalValue=1 or profileent7_.path='UUUUUUUU/KKKKKK/UUUUU' and profileent7_.numericalValue=1 or profileent7_.path='UUUUUUUU/KKKKKK/UUUUSSSS' and profileent7_.numericalValue=1) 
and profileent6_.path='UUUUUUUU/VVVVV/VVVV' and profileent6_.numericalValue>=0 and profileent6_.numericalToValue<=20000000 
and profileent5_.path='UUUUUUUU/IIIII/RRRRR' and profileent5_.value='abcd' 
and profileent4_.path='UUUUUUUU/MMMMMM/DDDDRRRR' and profileent4_.numericalValue>=0 and profileent4_.numericalValue<=24 
and profileent3_.path='UUUUUUUU/MMMMMM/RRRRRRRR' and profileent3_.numericalValue>=0 and profileent3_.numericalValue<=18 
and profileent2_.path='UUUUUUUU/LLLL/MMMMMMMM' and profileent2_.numericalValue>=0 and profileent2_.numericalValue<=100 
and (profileent1_.path='UUUUUUUU/BBBBB/A1' and profileent1_.numericalValue=1 or profileent1_.path='UUUUUUUU/BBBBB/A2' and profileent1_.numericalValue=1 or profileent1_.path='UUUUUUUU/BBBB/A3' and profileent1_.numericalValue=1)

返回

EXPLAIN SELECT ...

如果我理解正确,MySQL不使用profileent1_,profileent7_和profileent8_的路径索引,而是使用外键索引 FKpe40modwh6dhstsmypo9aub9i 。这些是连接,它们在其where-conditions中使用OR子句。

  • 如果我用同等的IN-Clause替换OR-Clause没有帮助,结果相同。
  • 如果我只是踢出OR-Clause的第二和第三部分(和 得到更少的结果)查询再次快速。

我有几个问题:

  1. 我的分析是否正确,OR-Clauses可能破坏连接性能?
  2. 是否有任何选项可以让MySQL提示使用更好的索引进行查询优化?或者:我可以重述此查询条件以获得更好的优化吗?
  3. 最难的一个:是否有一种“简单”的方式告诉Hibernate提供这些优化?
  4. 为了完整起见:以下是相关的DDL-statments

     # id, select_type, table,           type,     possible_keys,                                                      key,                           key_len, ref,                                    rows,  Extra
    '1',   'SIMPLE',    'profileent5_' , 'ref',    'path,value,FKpe40modwh6dhstsmypo9aub9i',                           'value',                       '103',   'const',                                '1',   'Using where; Using temporary'
    '1',   'SIMPLE',    'profileent6_' , 'range',  'path,FKpe40modwh6dhstsmypo9aub9i,numericalValue,numericalToValue', 'numericalToValue',            '9',     NULL,                                   '16',  'Using where; Distinct; Using join buffer'
    '1',   'SIMPLE',    'profileent10_', 'range',  'path,FKpe40modwh6dhstsmypo9aub9i,numericalValue',                  'path',                        '103',   NULL,                                   '40',  'Using where; Distinct; Using join buffer'
    '1',   'SIMPLE',    'profileent11_', 'range',  'path,FKpe40modwh6dhstsmypo9aub9i,numericalValue',                  'path',                        '103',   NULL,                                   '40',  'Using where; Distinct; Using join buffer'
    '1',   'SIMPLE',    'profileent4_' , 'ref',    'path,FKpe40modwh6dhstsmypo9aub9i,numericalValue',                  'path',                        '103',   'const',                                '20',  'Using where; Distinct'
    '1',   'SIMPLE',    'profileent9_' , 'ref',    'path,value,FKpe40modwh6dhstsmypo9aub9i',                           'path',                        '103',   'const',                                '20',  'Using where; Distinct'
    '1',   'SIMPLE',    'profileent2_' , 'ref',    'path,FKpe40modwh6dhstsmypo9aub9i,numericalValue',                  'path',                        '103',   'const',                                '20',  'Using where; Distinct'
    '1',   'SIMPLE',    'profileent3_' , 'ref',    'path,FKpe40modwh6dhstsmypo9aub9i,numericalValue',                  'path',                        '103',   'const',                                '20',  'Using where; Distinct'
    '1',   'SIMPLE',    'profileent1_' , 'ref',    'path,FKpe40modwh6dhstsmypo9aub9i,numericalValue',                  'FKpe40modwh6dhstsmypo9aub9i', '9',     'SUPlattform.profileent9_.profile_id',  '251', 'Using where; Distinct'
    '1',   'SIMPLE',    'profileent7_' , 'ref',    'path,FKpe40modwh6dhstsmypo9aub9i,numericalValue',                  'FKpe40modwh6dhstsmypo9aub9i', '9',     'SUPlattform.profileent1_.profile_id',  '251', 'Using where; Distinct'
    '1',   'SIMPLE',    'profileent8_' , 'ref',    'path,FKpe40modwh6dhstsmypo9aub9i,numericalValue',                  'FKpe40modwh6dhstsmypo9aub9i', '9',     'SUPlattform.profile0_.id',             '251', 'Using where; Distinct'
    '1',   'SIMPLE',    'profile0_'    , 'eq_ref', 'PRIMARY',                                                          'PRIMARY',                     '8',     'SUPlattform.profileent5_.profile_id',  '1',   ''
    

    感谢您的支持

    瓦伦斯坦

2 个答案:

答案 0 :(得分:2)

我的一位同事刚刚发现了这个问题:

它只与 where -clauses间接相关,而是与多个连接相关。如blog from Peter Zaitsev (a former developer of MySQL)中所述:查询优化的复杂性随着n的增长而增长!其中n是连接数。

因此,解决方案是建议查询优化器不要通过将 optimizer_search_depth 设置为某个有限的值来夸大优化。

瓦伦斯坦

答案 1 :(得分:0)

optimizer_search_depth=1

加速优化工具。

INDEX(profile_id, path, value),
INDEX(profile_id, path, numericalValue, numericalToValue),
INDEX(profile_id, path, toValue),

加快查询速度(部分)

如果您想进一步改进,请放弃EAV架构设计。

  

我的分析是否正确,OR-Clauses可能破坏连接性能? - 非常

     

是否有任何选项可以让MySQL提示使用更好的索引进行查询优化?或者:我可以重述此查询条件以获得更好的优化吗? - 没有

     

最难的一个:是否有一种“简单”的方式告诉Hibernate提供这些优化? - 我有第三方软件的选择词阻碍了。我会饶恕你的亵渎。

我为EAV添加了一个标签;仔细阅读该领域的其他问题。