【问题标题】:Query is very slow when I add a third LEFT JOIN添加第三个 LEFT JOIN 时查询很慢
【发布时间】:2014-04-30 03:58:01
【问题描述】:

您好,我一直在玩这个查询时间,但我无法让它在合理的执行时间内返回结果。

情况如下:

我有三张桌子 -

表 1 调用:rowsall

 1  id          int(11) 
 2  masterCaseId    varchar(50)
 3  RowNum  int(11)
 4  fullCaseNumber  varchar(50)
 5  rowKtavNameFull varchar(250)
 6  DateOpen    varchar(50)
 7  DateProccess    varchar(50)
 8  rowStatus   varchar(50)
 9  rowCourt    varchar(100)
 10 rowProcedure    varchar(50)
 11 rowCaseType varchar(50)
 12 rowIntrest  varchar(50)
 13 rowDetailsGen   varchar(250)
 14 rowTypeTeanot   varchar(50)
 15 rowHisayon  varchar(50)
 16 rowAmount   varchar(50)
 17 rowZacautPtor   varchar(50)
 18 rowZacautApproove   varchar(50)
 19 rowStatIravon   varchar(50)
 20 rowDateClose    varchar(50)
 21 rowCloseReason  varchar(50)
 22 rowResultTaken  varchar(50)
 23 rowOldFile          varchar(50)
 24 rowOpenedInCourse   varchar(50)
 25 rowGniza            varchar(50)
 26 rowReasonDeposit    varchar(50)
 27 rowTypeJudgeType    varchar(50)
 28 rowJudgeTypeDate
 29 rowJudgeTypeName    varchar(50)
 30 rowGishurType   varchar(50)
 31 rowGishurDetails    varchar(250)

   Total rows: 13001, size 11.7mb

   Indexes:
   PRIMARY  BTREE   Yes No  id  13001   A   No  
   RowNum   BTREE   No  No  RowNum  12  A   No  
                            rowStatus   12  A   No
                            rowResultTaken  12  A   No
   rowJudgeTypeName BTREE   No  No  rowJudgeTypeName    1083    A   No  
   masterCaseId BTREE   No  No  masterCaseId    13001   A   No  
   RowNum_2 BTREE   No  No  rowJudgeTypeName    1857    A   No  
                            RowNum  1857    A   No
   fullCaseNumber   BTREE   No  No  fullCaseNumber  203 A   No  

表 2 调用:casses_rows

 1  id  int(11)
 2  caseFullNum varchar(50)
 3  statusCrawl varchar(50)
 4  courtPlace  text
 5  rowsNum int(11)
 6  caseJudge   varchar(50)
 7  caseFullName    text
 8  whenCrawled datetime
 9  yearVal varchar(5)
 10 monthVal    varchar(5)
 11 caseVal int(11)

   Total rows: ~23,846, size 4.8mb

   Indexes:
   PRIMARY  BTREE   Yes No  id  26302   A   No  

表 3 调用:casedocs

 1  id  int(11)
 2  caseNum varchar(20)
 3  DocTitle    varchar(250)
 4  DocDateStr  varchar(20)
 5  KeyWords    text
 6  content text
 7  DocDateParsed   timestamp

   Total rows: ~1,163,669, size 4.1g

   Indexes:
   PRIMARY  BTREE   Yes No  id  895132  A   No  
   caseNum  BTREE   No  No  caseNum 895132  A   No  

我的目标:

我需要加入这些表以获得 table1 中的大部分 cols + table 2 中的一个 col + table 3 中的一个 col 如果没有匹配项,则为 NULL:

我的查询是:

SELECT 
       A.`id` AS idRowCase, 
       C.`caseNum` AS isPaperAva, 
       A.`rowCaseType`, 
       A.`fullCaseNumber`, 
       A.`rowProcedure`, 
       B.`caseFullName`, 
       A.`rowCourt`, 
       A.`rowAmount`, 
       A.`rowResultTaken`, A.`rowStatus`, A.`rowIntrest` ,A.`DateOpen` ,A.`DateProccess`, A.`rowDateClose`, A.`rowJudgeTypeDate` 

FROM (SELECT * FROM `rowsall` WHERE `rowJudgeTypeName` LIKE '%@value1%' AND `RowNum` ='1' ) A 
INNER JOIN ( SELECT `id`,`caseFullName` FROM `casses_rows` ) B 
      ON A.`masterCaseId` = B.`id` 
LEFT JOIN (SELECT `caseNum` FROM `casedocs` GROUP BY `caseNum` ORDER BY NULL ) C 
      ON A.`fullCaseNumber` = C.`caseNum`

结果如我所愿,但问题是返回结果需要 1 分钟...

这里是解释:

  id   select_type  table       type   possible_keys  key     key_len  ref  rows   Extra
  1    PRIMARY      <derived2>  ALL    NULL           NULL    NULL     NULL 121
  1    PRIMARY      <derived3>  ALL    NULL           NULL    NULL     NULL 24185  Using where; Using join buffer
  1    PRIMARY      <derived4>  ALL    NULL           NULL    NULL     NULL 343438
  4    DERIVED      casedocs    index  NULL           caseNum 62       NULL 768024 Using index
  3    DERIVED      casses_rows ALL    NULL           NULL    NULL     NULL 29872  
  2    DERIVED      rowsall     ref    RowNum         RowNum  4             6500   Using where

如您所见,我正在对表 3 进行分组,以防止连接在结果中创建重复行 - 实际上,第三个连接是测试是否存在与案例对应的文档(将为 NULL)。

更多信息:

  • 如果我删除第三个连接查询需要 1 秒
  • 如果我只执行第三个 join select 语句,则需要 0.003 秒
  • 分析查询时,“发送数据”占 99.9% 的时间。

任何想法为什么执行第三次连接需要这么长时间????

任务完成! 感谢@Turophile 和@Joel Coehoorn,新的测试结果大约是 0.004 秒!!!

这是最终的查询:

SELECT DISTINCT A.`id` AS idRowCase, C.`caseNum` AS isPaperAva, A.`rowCaseType` ,  A.`fullCaseNumber` , A.`rowProcedure` , B.`caseFullName` , A.`rowCourt` , A.`rowAmount` , A.`rowResultTaken` , A.`rowStatus` , A.`rowIntrest` , A.`DateOpen` , A.`DateProccess` , A.`rowDateClose` , A.`rowJudgeTypeDate` 

FROM  `rowsall` A
INNER JOIN  `casses_rows` B ON A.`masterCaseId` = B.`id` 
LEFT JOIN  `casedocs` C ON A.`fullCaseNumber` = C.`caseNum` 
WHERE A.`rowJudgeTypeName` LIKE  '%@value1%'
AND A.`RowNum` =  '1'

【问题讨论】:

    标签: mysql sql join


    【解决方案1】:

    我的建议是不要进行不必要的排序和分组。所以,是这样的:

    SELECT 
       A.`id` AS idRowCase, 
       C.`caseNum` AS isPaperAva, 
       A.`rowCaseType`, 
       A.`fullCaseNumber`, 
       A.`rowProcedure`, 
       B.`caseFullName`, 
       A.`rowCourt`, 
       A.`rowAmount`, 
       A.`rowResultTaken`, 
       A.`rowStatus`, 
       A.`rowIntrest`,
       A.`DateOpen` ,
       A.`DateProccess`, 
       A.`rowDateClose`, 
       A.`rowJudgeTypeDate` 
    
    FROM `rowsall` AS A 
    INNER JOIN `casses_rows` AS B 
          ON A.`masterCaseId` = B.`id` 
    LEFT JOIN `casedocs` AS C 
          ON A.`fullCaseNumber` = C.`caseNum`
    WHERE `rowJudgeTypeName` LIKE '%@value1%' 
    AND   `RowNum` ='1' 
    

    (如果 caseNum 不是唯一的,则可能返回不同的结果(多行)。

    您也可以将LEFT JOIN 变成子选择:

    SELECT 
       A.`id` AS idRowCase, 
       A.`fullCaseNumber` AS isPaperAva, 
       A.`rowCaseType`, 
       A.`fullCaseNumber`, 
       A.`rowProcedure`, 
       B.`caseFullName`, 
       A.`rowCourt`, 
       A.`rowAmount`, 
       A.`rowResultTaken`, 
       A.`rowStatus`, 
       A.`rowIntrest`,
       A.`DateOpen` ,
       A.`DateProccess`, 
       A.`rowDateClose`, 
       A.`rowJudgeTypeDate` 
    
    FROM `rowsall` AS A 
    INNER JOIN `casses_rows` AS B 
          ON A.`masterCaseId` = B.`id` 
    WHERE `rowJudgeTypeName` LIKE '%@value1%' 
    AND   `RowNum` ='1' 
    AND   A.`fullCaseNumber` in (SELECT `caseNum` FROM `casedocs` ) 
    

    但这表明使用表 casedocs 有点多余 - 真的需要吗?

    【讨论】:

    • 您好,不幸的是,删除第三个表并没有产生我想要的结果 - 正如我在问题中所写的那样,第三个表实际上已连接(左连接)到结果中,只是为了检查是否有与 casenumber 相关的文档 - 如果他会找到结果,那么会有一个值,否则它将为 NULL ...我必须对它进行 GROUP 或 DISTINCT,因为可能有很多与相同 casenumber 相关的文档,我想检查只有存在与否 - 如果我不分组,我将有很多重复的结果,我无法分组......
    • 难以置信,我在您的解决方案中添加了一个词,现在可以了!!!! 0.0046 秒!!!!!!但我不能接受你的回答,因为问题是由@Joel_Coehoorn 发现的,最后是分组问题,删除子查询将其提升到但主要是分组。
    • 很高兴我能帮上忙。请注意,您的最终查询清晰而简单 - 当您遇到困难时,请尝试使您的 SQL 更清晰和简单 - 这通常会有所帮助。
    【解决方案2】:

    首先,前两个表根本不需要子查询。这可以直接通过连接条件和 WHERE 子句更好地表达。

    另外,最后一个连接使用了一个带有 group by 的子查询:

    左连接(选择 caseNum FROM casedocs GROUP BY caseNum ORDER BY NULL)

    这破坏了 MySql 在计算最后一个连接时使用任何索引的能力。如果您可以重新编写它以首先加入表,并在外部查询中执行 GROUP BY,以便获得相同的结果,它可能会执行 much 更好,因为您将拥有更好的使用索引。

    SELECT 
           A.`id` AS idRowCase, 
           C.`caseNum` AS isPaperAva, 
           A.`rowCaseType`, 
           A.`fullCaseNumber`, 
           A.`rowProcedure`, 
           B.`caseFullName`, 
           A.`rowCourt`, 
           A.`rowAmount`, 
           A.`rowResultTaken`, A.`rowStatus`, A.`rowIntrest` ,A.`DateOpen` ,A.`DateProccess`, A.`rowDateClose`, A.`rowJudgeTypeDate` 
    
    FROM `rowsall` A 
    INNER JOIN `casses_rows` B   ON A.`masterCaseId` = B.`id` 
    LEFT JOIN (SELECT `caseNum` FROM `casedocs` GROUP BY `caseNum` ) C ON c.`caseNum` = A.`fullCaseNumber`
    WHERE A.`rowJudgeTypeName` LIKE '%@value1%' AND A.`RowNum` ='1' 
    

    【讨论】:

    • 您好,不幸的是,删除第三个表并没有产生我想要的结果 - 正如我在问题中所写的那样,第三个表实际上已连接(左连接)到结果中,只是为了检查是否有与 casenumber 相关的文档 - 如果他会找到结果,那么会有一个值,否则它将为 NULL ...我必须对它进行 GROUP 或 DISTINCT,因为可能有很多与相同 casenumber 相关的文档,我想检查只有存在与否 - 如果我不分组,我将有很多重复的结果,我无法在之后分组......
    • 为什么 GROUP BY 会阻止索引的使用?
    • 我尝试了您编辑的查询(没有子查询),这次花了​​更多时间 1.5 分钟。
    • 最后它的工作谢谢你 - 我将你的答案与@Turophile 答案合并并让它以我可以想象的速度工作 0.0046 秒 - 主要问题是按问题分组并删除子查询也提升了它。
    猜你喜欢
    • 2013-02-15
    • 2014-05-09
    • 1970-01-01
    • 1970-01-01
    • 2014-03-15
    • 2015-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多