优化SQL查询

时间:2009-02-12 10:30:18

标签: sql mysql optimization left-join inner-join

我还可以做些什么来优化此查询?

SELECT * FROM
    (SELECT `item`.itemID, COUNT(`votes`.itemID)  AS `votes`,
           `item`.title, `item`.itemTypeID, `item`.
           submitDate, `item`.deleted, `item`.ItemCat,
           `item`.counter, `item`.userID, `users`.name,
           TIMESTAMPDIFF(minute,`submitDate`,NOW()) AS 'timeMin' ,
           `myItems`.userID as userIDFav, `myItems`.deleted as myDeleted
      FROM    (votes `votes` RIGHT OUTER JOIN item `item`
                  ON (`votes`.itemID = `item`.itemID))
           INNER JOIN
              users `users`
           ON (`users`.userID = `item`.userID)
    LEFT OUTER JOIN
              myItems `myItems`
           ON (`myItems`.itemID = `item`.itemID)
     WHERE (`item`.deleted = 0)
     GROUP BY `item`.itemID,
              `votes`.itemID,
              `item`.title,
              `item`.itemTypeID,
              `item`.submitDate,
              `item`.deleted,
              `item`.ItemCat,
              `item`.counter,
              `item`.userID,
              `users`.name,
              `myItems`.deleted,
              `myItems`.userID
    ORDER BY `item`.itemID DESC) as myTable
where myTable.userIDFav = 3 or myTable.userIDFav is null
            limit 0, 20 

我正在使用MySQL

由于

6 个答案:

答案 0 :(得分:9)

分析器对此查询说了什么?如果不了解表中有多少行,就无法进行任何优化。因此,运行分析仪,您将看到哪些部分成本是多少。

答案 1 :(得分:5)

当然,正如@theomega所说,看看执行计划。

但我也建议尝试“清理”你的陈述。 (我不知道哪一个更快 - 这取决于你的表大小。)通常,我会尝试从一个干净的语句开始并从那里开始优化。但通常情况下,一个干净的语句使优化器更容易提出一个好的执行计划。

所以这里有一些关于你的陈述的观察可能会让事情变得缓慢:

  • 几个外连接(使得优化器难以找出要使用的索引)
  • a group by
  • 很多要分组的列

据我了解你的SQL,这个陈述应该完成你的大部分工作:

SELECT `item`.itemID, `item`.title, `item`.itemTypeID, `item`.
       submitDate, `item`.deleted, `item`.ItemCat,
       `item`.counter, `item`.userID, `users`.name,
       TIMESTAMPDIFF(minute,`submitDate`,NOW()) AS 'timeMin' 
  FROM    (item `item` INNER JOIN users `users`
       ON (`users`.userID = `item`.userID)

在哪里

当然,这会错过您加入的表中的信息,我建议尝试通过子选择添加所需的列:

SELECT `item`.itemID, 
       (SELECT count (itemID)
        FROM votes v
       WHERE v.itemID = 'item'.itemID) as 'votes', <etc.>

这样,您可以删除一个外部联接和组。外部联接由子选择替换,因此存在权衡,这可能对“清洁”声明不利。

根据item和myItems之间的基数,您可以执行相同操作,或者您必须坚持使用外连接(但不需要重新引入组)。

希望这有帮助。

答案 2 :(得分:1)

一些快速的半随机想法:

您的itemID和userID列是否已编入索引?

如果在查询开头添加“EXPLAIN”并运行它会发生什么?它是否使用索引?他们是明智的吗?

您是否需要运行整个内部查询并对其进行过滤,或者您是否可以将where myTable.userIDFav = 3 or myTable.userIDFav is null部分移动到内部查询中?

答案 3 :(得分:0)

你似乎在Group By列表中有太多字段,因为其中一个是itemID,我怀疑你可以使用内部SELECT来预先形成分组,而外部SELECT则返回所需的字段集。 / p>

答案 4 :(得分:0)

你不能将where子句 myTable.userIDFav = 3或myTable.userIDFav为空添加到 WHERE(item。deleted = 0)

问候
利芬

答案 5 :(得分:0)

查看构建查询的方式。你加入了很多东西,然后将输出限制为20行。您应该在项目和myitems上具有外部联接,因为您的条件仅适用于这两个表,将输出限制为前20行,然后加入和聚合。在这里,你正在完成许多将被丢弃的工作。