Mysql嵌套查询需要很长时间

时间:2015-05-08 12:19:49

标签: mysql sql mysql-workbench

我们正在使用以下问题从大型mysql表中获取日期。

SELECT fullPath, Permissiontype, DinstinguishedName 
from cdm.test 
where fullPath in 
  (SELECT distinct fullPath 
   FROMcdm.test 
   WHERE (Permissiontype = 'EXPLICIT' and not DinstinguishedName ='') 
   OR(Permissiontype = 'INHERITED' 
     AND (length(fullPath) - length(replace(fullPath,'/','')) < 4)) 
   OR(Permissiontype = 'EXPLICIT' 
     AND NOT DinstinguishedName='' 
     AND LEFT(fullPath,length(fullPath)-Length(RIGHT(fullPath,INSTR(reverse(fullPath),'/')))) 
AND(length(fullPath) - length(replace(fullPath,'/','')) > 2) ))

当我将需要显示的结果限制为270时,它运行得非常快,但是例如500行它不会运行。我在表中有1个77mil的行(需要在1个表中)。然后它运行了8个多小时仍然没有完成。有没有办法优化这个?

WKR。

3 个答案:

答案 0 :(得分:1)

对于测试表中的每条记录,您将在子查询中再次查询整个表。不要在where子句中使用子查询,而是在同一个表上尝试内部联接。这将大大提高您的表现。

我还没有尝试过,但它可能看起来像:

SELECT fullPath, Permissiontype, DinstinguishedName from cdm.test 
INNER JOIN (
SELECT distinct fullPath from cdm.test 
where (Permissiontype = 'EXPLICIT' and not DinstinguishedName ='') 
or (Permissiontype = 'INHERITED' AND (length(fullPath) - length(replace(fullPath,'/','')) < 4)) OR(Permissiontype = 'EXPLICIT' 
AND NOT DinstinguishedName='' AND LEFT(fullPath,length(fullPath)-length(RIGHT(fullPath,INSTR(reverse(fullPath),'/')))) 
and(length(fullPath) - length(replace(fullPath,'/','')) > 2) )
) AS SQ1 
ON SQ1.fullpath = cdm.test.fullpath

答案 1 :(得分:0)

对于IN语句和子查询的组合,mysql有一个名为EXISTS()的有用优化器(不是专门用于此但可用于优化将子语句与子语句结合使用的查询)

根据https://dev.mysql.com/doc/refman/5.0/en/subquery-optimization-with-exists.html

的参考资料
outer_expr IN (SELECT inner_expr FROM ... WHERE subquery_where)

相同
 EXISTS (SELECT 1 FROM ... WHERE subquery_where AND outer_expr=inner_expr)

但更快

您的查询存在:

SELECT fullPath, Permissiontype, DinstinguishedName 
FROM cdm.test cdm1
WHERE EXISTS(SELECT 0 FROM cdm.test cdm2 @wherecondition AND cdm2.fullPath = cdm1.fullPath)

@wherecondition =

WHERE (Permissiontype = 'EXPLICIT' and not DinstinguishedName ='') 
   OR(Permissiontype = 'INHERITED' 
     AND (length(fullPath) - length(replace(fullPath,'/','')) < 4)) 
   OR(Permissiontype = 'EXPLICIT' 
     AND NOT DinstinguishedName='' 
     AND LEFT(fullPath,length(fullPath)-Length(RIGHT(fullPath,INSTR(reverse(fullPath),'/')))) 
AND(length(fullPath) - length(replace(fullPath,'/','')) > 2)) 

答案 2 :(得分:0)

有几个问题会导致查询执行非常慢

  1. 您正在使用in子句,但在很多情况下它们都很糟糕,所以最好将它们转换为JOIN子句。

  2. 即使使用JOIN,内部查询也有多个OR条件,优化器也无法使用索引。

  3. 为什么你需要in clause

  4. 同一个查询可以写成

    select fullPath,Permissiontype,DinstinguishedName from cdm.test  
        where  
        Permissiontype = 'EXPLICIT' 
        and not DinstinguishedName ='' 
    
        union 
        select fullPath,Permissiontype,DinstinguishedName from cdm.test  
        where Permissiontype = 'INHERITED' 
        AND (length(fullPath) - length(replace(fullPath,'/','')) < 4)
    
        union
        select fullPath,Permissiontype,DinstinguishedName from cdm.test 
        where Permissiontype = 'EXPLICIT'  
        AND NOT DinstinguishedName=''   
        AND LEFT(fullPath,length(fullPath)-length(RIGHT(fullPath,INSTR(reverse(fullPath),'/')))) 
        and(length(fullPath) - length(replace(fullPath,'/','')) > 2) 
    

    请注意,我已将所有OR条件更改为union,这样会更快。

    现在添加一个索引,如果它尚未添加为

    alter table cdm.test add index search_data_idx(Permissiontype,DinstinguishedName,fullPath);