【问题标题】:How can I optimize this MySQL query? Should I use joins?如何优化这个 MySQL 查询?我应该使用联接吗?
【发布时间】:2018-09-10 22:30:04
【问题描述】:

我想优化以下 MySQL 查询,它从 2 个表中挑选数据,其中 authorchecklist 表有详细记录,而 selectedrevlist 表用于审阅者的评论。

我想从scoreSubmit = 1的selectedrevlist中获取这些记录

SELECT  *
    FROM  `authorchecklist` acl
    WHERE  acl.manuscriptStatus = 'Awaiting Reviewer Assignment'
      AND  acl.submitStatus = '1'
      AND  
        ( SELECT  COUNT( 1 )
            FROM  selectedrevlist srl
            WHERE  srl.OrderNumber = acl.OrderNumber
              AND  srl.editorType = 'Editor'
              AND  srl.editorID = '10'
              AND  srl.scoreSubmit = '1' 
        ) = 1 

上述查询工作正常,但加载记录大约需要 20 秒。

【问题讨论】:

  • 能否在两个表中添加表结构和一些插入查询?
  • 请在代码问题中给出minimal reproducible example--剪切&粘贴&可运行代码;具有期望和实际输出(包括逐字错误消息)的示例输入(作为初始化代码);标签和版本;明确的规范和解释。对于包含 DBMS 和 DDL 的 SQL,其中包括约束、索引和表格初始化。对于包括 EXPLAIN 结果和统计信息的 SQL 性能。 (约束、索引和计划至关重要。)在考虑发布之前请先研究一下。这包括 SQL 优化/性能的基础——直接导致索引、计划、统计和 SARGability。 How to Ask

标签: mysql sql performance join


【解决方案1】:

这是您的查询:

SELECT acl.*
FROM authorchecklist acl
WHERE acl.manuscriptStatus = 'Awaiting Reviewer Assignment' AND
      acl.submitStatus = 1 AND
      (SELECT COUNT(1) 
       FROM selectedrevlist srl 
       WHERE srl.OrderNumber = acl.OrderNumber AND
             srl.editorType =  'Editor' AND
             srl.editorID = 10 AND
             srl.scoreSubmit = 1
      ) = 1 ;

对于此查询,您需要authorchecklist(submitStatus, manuscriptStatus, OrderNumber)selectedrevlist(OrderNumber, editorId, scoreSubmit) 上的索引。

【讨论】:

  • 使用索引 authorchecklist(submitStatus, transcriptStatus, OrderNumber),他需要更改查询才能使用索引。 acl.submitStatus 应该首先进行比较(比较的顺序应该与索引中的字段顺序匹配)。我也很确定他不需要索引,例如 scoreSubmit 和 editorID。
  • @PedroAmaralCouto 您能否为查询顺序必须与索引顺序匹配的说法提供参考?因为,我认为您可能误解了索引顺序 c.f. 的最左原则,stackoverflow.com/q/2292662/2908724
  • @PedroAmaralCouto 。 . .这完全是错误的。 WHERE 中相等条件的顺序无关紧要。它们可以按任意顺序匹配索引。
  • @bishop,看来你是对的:stackoverflow.com/questions/1252279/mysql-indices-and-order“查询中的条件顺序无关紧要”
  • 数一下COUNT返回的值是否大于1?
【解决方案2】:

我重新排列了查询以使其更易于阅读:

SELECT *
FROM  `authorchecklist` acl
WHERE acl.manuscriptStatus =  'Awaiting Reviewer Assignment'
      AND acl.submitStatus = '1'
      AND (
          SELECT COUNT( 1 )
          FROM selectedrevlist srl 
          WHERE srl.OrderNumber = acl.OrderNumber
          AND  srl.editorType =  'Editor' 
          AND  srl.editorID =  '10' AND srl.scoreSubmit = '1'
      ) = 1

我假设每个作者清单只有一个 selectedrevlist。

您没有发送表定义(“CREATE TABLE ...”),但可能至少其中一个字段没有被索引:

authorchecklist.manuscriptStatus
selectedrevlist.OrderNumber

如果它们没有被索引,SQL 服务器将需要遍历所有记录。它将遍历所有 authorchecklist 行,并且对于每个 authorchecklist 行,它将遍历所有 selectedrevlist 行以找到“srl.OrderNumber = acl.OrderNumber”。索引可能会使插入速度变慢,但如果使用得当,它们会加快读取速度。

[删除了错误的断言]

如果您使用的是 MySQL,请在确定始终只获取一条记录时添加“LIMIT 1”。此外,使用 InnoDB 引擎并添加外键 - 这些是验证关系的索引。

看看这些:

【讨论】:

  • 感谢您的回复,实际上我正在寻找这样一个查询,它可以获取具有 1、2 或 3 个响应的记录。例如,我想获取那些有 1、2、3 个回复的消息。
  • 这是因为我想针对每条记录显示计数器,当点击计数器时,它应该详细显示第 1、2 或 3 条记录。我希望你明白我的意思。
【解决方案3】:

添加这些索引:

ALTER TABLE
  `authorchecklist`
ADD
  INDEX `authorchecklist_idx_manuscriptstatu_submitstatus` (`manuscriptStatus`, `submitStatus`);

ALTER TABLE
  `authorchecklist`
ADD
  INDEX `authorchecklist_idx_ordernumber` (`OrderNumber`);

ALTER TABLE
  `selectedrevlist`
ADD
  INDEX `selectedrevlist_idx_editort_editori_scoresu_ordernu` (
    `editorType`,
    `editorID`,
    `scoreSubmit`,
    `OrderNumber`
  );

使用 EXISTS 而不是计算记录的子查询。 Exists 子查询将在找到后退出,而不是计算与过滤器匹配的所有行。

SELECT 
    *
FROM
    `authorchecklist` acl
WHERE
    acl.manuscriptStatus = 'Awaiting Reviewer Assignment'
        AND acl.submitStatus = '1'
        AND EXISTS (SELECT *
        FROM
            selectedrevlist srl
        WHERE
            srl.OrderNumber = acl.OrderNumber
                AND srl.editorType = 'Editor'
                AND srl.editorID = '10'
                AND srl.scoreSubmit = '1') 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-09
    • 2010-11-15
    • 1970-01-01
    相关资源
    最近更新 更多