3

以下は、完了までに約 1 ミリ秒かかる mysql クエリです。

SELECT SQL_NO_CACHE DISTINCT invoice.*,
GROUP_CONCAT(DISTINCT line.guid) as line 
FROM invoice  
LEFT JOIN ligne ON line.invoice = invoice.guid 
GROUP BY invoice.guid 
WHERE acompte = 1
LIMIT 0, 100;

クエリに追加ORDER BY invoice.dateすると、非常に遅くなり、完了するまでに約 3 秒かかります。

LEFT JOIN(および)を削除するとGROUP_CONCAT、クエリは再び 1 ミリ秒かかります。

EXPLAINクエリが遅いときにMySQLが何をしているのかを確認するために追加しました。一時ファイルを使用していることがわかります。

1   SIMPLE  invoice index   NULL    PRIMARY 4   NULL    25385   Using temporary; Using filesort
1   SIMPLE  line    ref invoice invoice 5   gestixi.invoice.guid    1   Using index

そのクエリを高速化する方法があると確信していますが、見つかりません。何か案が ?

dateユーザーがテーブルの各フィールドをソートできるようにするため、インデックスを追加できないことに注意してください(ちなみに、何も変更しません)。

invoice.guidまた、 、line.invoiceline.guidおよびacompteにはインデックスが付けられていることに注意してください。

編集

LEFT JOIN を使用せずに ORDER BY 句を使用して最初のクエリを実行し、必要な行の ID を取得してから、WHERE 句でこれらの ID を使用して 2 番目のクエリ (上記のような) を実行すると、取得できるものを取得できます。 10ms未満で必要です。

これは、インデックスを追加せずにそのクエリを高速化する方法であるに違いないと私は信じています。

4

1 に答える 1

1

ユーザーが任意のフィールドでソートできるようにする (そしてこのソートにインデックスを使用させる) 必要がある場合は、考えられるソートごとにインデックスが必要です。定義上、それ以外のことはできません。特定の行での並べ替えでは、この行のインデックスのみを使用できます。

ここにはほとんど選択肢がありません。ソートする行数を減らすか (25,000 行は結果セットとしては少し大きいですが、ユーザーは本当にそれほど多くの行を必要とするのでしょうか?)、すべての行でソートを許可しないようにしてください。

通常、クエリはテーブルごとに複数のインデックスを使用できないことに注意してください。他の人がアドバイスしたように、あなたが言及したクエリには複合インデックスの方が適していますが、逆の順序 ( (guid, date)) をお勧めします (クエリは最初に各 を選択しguid、次にそれぞれに対応する行をソートする必要があります)。

にも索引を追加しますline(guid, acompte, invoice)

(インデックス作成に関する上記の提案は、MyISAM テーブルを想定しています)

クエリ自体の最適化に関しては、単純な実行計画を考えると、これ以上行うことはほとんどありません。

このバージョンでより良い結果が得られる場合とそうでない場合があります。

SELECT
    invoice.*, -- DISTINCT is redudant here because of the GROUP BY clause
    GROUP_CONCAT(ligne_acompte.guid) as line  -- DISTINCT is (presumably) redundant here because guid is (presumably) unique
FROM invoice  
LEFT JOIN (
    SELECT guid, invoice
    FROM line
    WHERE acompte = 1
) AS ligne_acompte ON ligne_acompte.invoice = invoice.guid 
GROUP BY invoice.guid
ORDER BY invoice.date;
于 2013-06-04T15:17:22.993 に答える