2

次の MySQL クエリで非常に遅いのは何ですか?

DocumentRevision.document と Document.status にインデックスを追加しようとしましたが、通常はクエリの実行に永遠に時間がかかります (このクエリを順番に実行すると、クエリが高速化されるようです)。同じ結果を達成するための別のより効率的な方法はありますか? クエリは、データベースで利用可能なすべてのドキュメントのすべての最新リビジョンを取得します。2 つのテーブルがあります。Document および DocumentRevision。Document テーブルには 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

4 に答える 4

0

結果が大きい場合、 a を使用したサブクエリがGROUP BY実行計画の問題を引き起こす可能性があると思います。サブクエリなしでクエリを試してみることをお勧めします。

( に索引がありDocument.id、役に立ちます。)DocumentRevision.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。サブクエリのないクエリのより単純な計画に注意してください。

于 2013-01-16T09:01:40.083 に答える
0

次の 2 つのオプションがあります。

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)クエリが高速に動作するように (この順序で) に複合インデックスを作成します。

于 2013-01-16T08:39:27.113 に答える
0

あなたの要件を見る:

2 つのテーブルがあります。Document および DocumentRevision。Document テーブルには id フィールドと status フィールドだけが含まれますが、DocumentRevision にはすべてのデータと "document" id フィールドが含まれているため、どのドキュメントのリビジョンかがわかります。

そしてあなたのコード、サブセレクトなしで別のクエリを書きました。document.ID と documentRevision.document で 1 つの選択と適切なインデックスを使用すると、結合のパフォーマンスが向上するため、より効果的です。

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
于 2013-01-16T08:45:04.213 に答える
0

クエリは、結合で documentRevision テーブルを複数回使用しました。最適化の余地は確かにあります。

他の DBMS (Teradata や MS SQL サーバーなど) では、sum(1) over(partition by rev.document order by rev.id desc).

MySQL にはウィンドウ集計関数がありません。ただし、パラメーターを使用しても同じことができます。

select * from (
  select
  if(@doc_id_grp=rev.document,@rank:=@rank+1,@rank:=1) rank /*the same document.id (documentRevision.document) is considered the same group, in the group, @rank increntally increases, when the doc_id changes, @rank resets to 0*/
  ,@doc_id_grp:=rev.document as doc_id
  ,rev.id as rev_id
  ,rev.name as name
  ,rev.datecreated as datecreated
  ,rev.documentorder as documentorder
  from Document doc
  join DocumentRevision rev
  on doc.id=rev.Document
  ,(select @rank:=0,@doc_id_grp:=0) a
  order by rev.document,rev.id desc
  where doc.status=0
) x
where rank=1

このように、DBMS はテーブルを 2 回結合するのではなく、1 回だけ結合してから並べ替えを行います。

これをテストする MySQL 環境はありませんが、必要に応じて微調整してください。これが役立つことを願っています。結合を最適化するために、Document.id と DocumentRevision.document にもインデックスを作成してください。

于 2013-01-16T09:12:37.233 に答える