17

以下は、ストアドプロシージャ内のSQLステートメントです(簡潔にするために切り捨てられています)。

SELECT * 
FROM item a 
WHERE a.orderId NOT IN (SELECT orderId FROM table_excluded_item);

このステートメントには30秒ほどかかります。しかし、内部のSELECTクエリを削除すると、1になります。table_excluded_itemそれほど大きくはありませんが、内部クエリが必要以上に実行されているのではないかと思います。

これを行うためのより効率的な方法はありますか?

4

3 に答える 3

23

使用するLEFT JOIN

SELECT  a.* 
FROM    item a 
        LEFT JOIN table_excluded_item b
            ON a.orderId = b.orderId
WHERE   b.orderId IS NULL

orderId両方のテーブルからインデックスが作成されていることを確認してください。

于 2013-01-05T02:04:25.920 に答える
5

左結合アプローチの問題は、出力の生成時に重複レコードが処理される可能性があることです。場合によっては、そうではありません。。。この記事によると、MySQLはleft outer join、重複が存在する場合でも、列にインデックスが付けられている場合に正しく最適化されます。ただし、この最適化は常に行われることに懐疑的なままであることを認めます。

INMySQLでは、サブクエリを使用してステートメントを最適化する際に問題が発生することがあります。最善の修正は、相関サブクエリです。

SELECT * 
FROM item a 
WHERE not exists (select 1
                  from table_excluded_item tei
                  where tei.orderid = a.orderid
                  limit 1
                 )

table_excluded_item.orderidにインデックスがある場合、これはインデックスをスキャンし、最初の値で停止します(limit 1これは厳密には必要ない場合があります)。これは、MySQLに必要なものを実装するための最も速くて安全な方法です。

于 2013-01-05T14:09:56.833 に答える
1

これを試して、LEFT JOINクエリ時間と比較してください。

SELECT * 
FROM item a 
HAVING orderId NOT IN (SELECT orderId FROM table_excluded_item);

制限条件( )が結果セットの一部であると想定しているため、これは(使用できる場合に使用して)HAVING嫌われます。しかし、このシナリオでは(結果セットの一部であるため)、アプローチよりも何が起こっているのかが明確であるため、より理にかなっていると思います。WHEREHAVINGorderIdLEFT JOIN

実際には少し遅いかもしれませんが、結果を投稿して、元のクエリよりも優れているかどうかを確認してください。

于 2013-01-05T02:47:39.413 に答える