Mysql 嵌套查询需要很长时间

Mysql nested queries take a long time

我们正在使用以下问题从大 mysql table.

中获取日期
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 个案例,我在 table 中有 7700 万行(需要在 1 table 中)。然后它 运行s 超过 8 小时,仍然没有完成。有没有办法优化这个?

wkr.

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

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

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

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

根据 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)) 

有几个问题会使查询执行速度非常慢

  1. 您正在使用 in 子句,它们在很多情况下都是错误的,因此最好将它们转换为 JOIN 子句。

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

  3. 为什么你需要 in clause

同样的查询可以写成

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);