【问题标题】:SQL query runs very slow using order by使用 order by 的 SQL 查询运行速度非常慢
【发布时间】:2014-06-18 10:41:02
【问题描述】:

我有两张桌子。 uploadsprofits

上传:

╔════╦══════════════╦══════════════════╗
║ id ║  name        ║ more columns...  ║
╠════╬══════════════╬══════════════════╣
║  1 ║ Jeff Atwood  ║ ................ ║
║  2 ║ Geoff Dalgas ║ ................ ║
║  3 ║ Jarrod Dixon ║ ................ ║
║  4 ║ Joel Spolsky ║ ................ ║
╚════╩══════════════╩══════════════════╝

利润:

╔══════════╦══════════════╦══════════════════╗
║ uploadid ║    amount    ║ more columns...  ║
╠══════════╬══════════════╬══════════════════╣
║    1     ║     4.0      ║ ................ ║
║    1     ║     7.2      ║ ................ ║
║    3     ║     6.3      ║ ................ ║
║    4     ║     2.5      ║ ................ ║
╚══════════╩══════════════╩══════════════════╝

如您所见,uploads.id => profits.uploadid

我想显示uploads 表中的一些行,再加一列告诉我有多少“利润”。

结果示例:

╔════╦══════════════╦════════════════╦══════════════════╗
║ id ║  name        ║  profitsCount  ║ more columns...  ║
╠════╬══════════════╬════════════════╬══════════════════╣
║  1 ║ Jeff Atwood  ║       2        ║ ................ ║
║  2 ║ Geoff Dalgas ║       0        ║ ................ ║
║  3 ║ Jarrod Dixon ║       1        ║ ................ ║
║  4 ║ Joel Spolsky ║       1        ║ ................ ║
╚════╩══════════════╩════════════════╩══════════════════╝

注意:在实际表中,uploads.idprofits.uploadid 列是 varchar 而不是 int,我在这里用 int 做的更清楚。

问题在于,当我使用大型表(数千行)运行查询时,它需要 大量时间

我的查询:

SELECT          `uploads`.* ,COUNT(`profits`.`uploadid`) AS `numProfits`
FROM            `uploads`
LEFT JOIN       `profits`
ON              `uploads`.`id` = `profits`.`uploadid`
GROUP BY        `uploads`.`id`
ORDER BY        `numProfits`
DESC
LIMIT           30

【问题讨论】:

  • 你的表有索引吗?
  • 并且顺便说一句,当您仅按单列分组时,MySQL 允许选择完整的记录——但这在 IMO 中是非常错误的。 :)
  • @juergend id 列是主列。 id 的示例:OQl1iYdWF
  • uploadid 也被编入索引?

标签: mysql sql performance select sql-order-by


【解决方案1】:

这是您的查询:

SELECT u.* ,COUNT(p.uploadid) AS numProfits
FROM uploads LEFT JOIN
     profits p
     ON u.id = p.uploadid
GROUP BY u.id
ORDER BY numProfits DESC
LIMIT 30;

第一个改进:在profits(uploadid) 上创建索引。这可能会解决您的问题。您或许可以通过以下方式获得更好的性能:

select u.*,
       (select count(*) from profits p where u.id = p.uploadid) as numProfits
from uploads u
order by numProfits desc
limit 30;

这消除了对文件排序聚合的需要。我更喜欢带有显式聚合的第一个版本,但子查询可以更好地工作。

您也可以在子查询中尝试聚合:

select u.*, numProfits
from uploads u join
     (select uploadid, count(*) as numProfits
      from profits p
      group by uploadid
      order by numProfits desc
      limit 30
     ) p
     on u.id = p.uploadid;
order by numProfits desc;

编辑:

对于最后一个解决方案,要选择没有利润的行,请使用 left joincoalesce()

select u.*, coalesce(numProfits, 0) as numProfits
from uploads u left join
     (select uploadid, count(*) as numProfits
      from profits p
      group by uploadid
      order by numProfits desc
      limit 30
     ) p
     on u.id = p.uploadid;
order by numProfits desc;

【讨论】:

  • 非常感谢!您的第二个查询完美地完成了这项工作。
  • 我注意到它只选择有利润的行。怎么全选,没有利润就写0或者null? (我说的是你的第二个查询)
【解决方案2】:

您可以通过按字段对 order 进行索引来最小化 SQL 选择查询时间,但这可能(并且将会)影响您的插入时间(并且在索引列受到影响时更新)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-19
    • 1970-01-01
    • 2019-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多