优化慢速MySQL查询

时间:2013-01-16 08:27:45

标签: mysql

以下MySQL查询的速度有多慢?

我已经尝试过将索引添加到DocumentRevision.document和Document.status但是它仍然需要永远执行查询(似乎如果按顺序进行查询,查询会加快速度)。还有另一种更有效的方法来实现相同的结果吗?该查询将获取数据库中所有可用文档的所有最新修订版本。有两张桌子。文档和文档修订。文档表只包含id和status字段,而DocumentRevision包含所有数据和“document”id字段,以便它知道哪个文档的修订版本。

SELECT rev.document as documentId, rev.id as revId, rev.name as name, 
       rev.dateCreated as dateCreated, rev.documentOrder as documentOrder
FROM (
    SELECT Document.id as docId, MAX(DocumentRevision.id) as maxRevId 
    FROM Document, DocumentRevision
    WHERE Document.id = DocumentRevision.document AND Document.status = 0 
    GROUP BY Document.id
) AS x 
INNER JOIN DocumentRevision as rev on rev.document = x.docId 
       AND rev.id = x.maxRevId 
ORDER BY dateCreated DESC;

4 个答案:

答案 0 :(得分:0)

您有两种选择:

SELECT  dr.*
FROM    (
        SELECT  document, MAX(id) AS maxid
        FROM    documentRevision
        GROUP BY
                document
        ) drd
JOIN    documentRevision dr
ON      dr.id = drd.maxid
JOIN    document d
ON      (d.id, d.status) = (drd.document, 0)

SELECT  dr.*
FROM    document d
JOIN    documentRevision dr
ON      dr.id =
        (
        SELECT  id
        FROM    documentRevision dri
        WHERE   dri.document = d.id
        ORDER BY
                document DESC, id DESC
        LIMIT 1
        )

第一个很可能是最有效的,除非你每个文档都有很多版本。

documentRevision (document, id)上创建一个复合索引(按此顺序),以使查询快速运行。

答案 1 :(得分:0)

查看您的要求:

  

有两张桌子。文档和文档修订。文件表   只包含id和status字段,而DocumentRevision包含   所有数据和“文档”id字段,以便它知道哪个   文件的修订版。

你的代码,我写了另一个没有subselect的查询。只需在document.ID和documentRevision.document上选择一个适当的索引就可以获得更好的连接性能。

SELECT rev.document docID, MAX(rev.id) revID, rev.name revName, rev.dateCreated dateCreated, rev.documentOrder docOrder
FROM DocumentRevisin as rev, Document as doc
WHERE doc.status = 0 AND doc.id = rev.document
GROUP BY rev.document, rev.name revName, rev.dateCreated dateCreated, rev.documentOrder docOrder

答案 2 :(得分:0)

我怀疑如果结果很大,带有GROUP BY的子查询可能会导致一些执行计划问题;您可能希望在没有子查询的情况下尝试查询。

Document.idDocumentRevision.documentDocumentRevision.status上的索引会有所帮助。)

SELECT rev.document as documentId, rev.id as revId, rev.name as name, 
   rev.dateCreated as dateCreated, rev.documentOrder as documentOrder
FROM Document doc
JOIN DocumentRevision rev
  ON doc.id=rev.document
LEFT JOIN DocumentRevision rev2
  ON rev.document = rev2.document AND rev.id < rev2.id
WHERE doc.status=0 AND rev2.id IS NULL
ORDER BY dateCreated DESC;

SQLfiddle to show identical results。请注意没有子查询的查询的简单计划。

答案 3 :(得分:0)

您的查询多次使用联接中的documentRevision表。肯定有优化的空间。

在其他DBMS(例如Teradata或MS SQL服务器中,这可以通过'{1}}形式的'窗口聚合'功能来完成。

MySQL没有窗口聚合功能。 但是可以使用参数完成相同的操作:

sum(1) over(partition by rev.document order by rev.id desc)

这样,DBMS不会加入表两次,只加入一次然后进行排序。

我没有MySQL环境来测试它,但是根据需要调整它。我希望这会有所帮助。 还请在Document.id和DocumentRevision.document上有索引以优化连接。