8

同じ機能を実行するために使用できる2つのクエリを作成しました。どちらにも、単一のクエリにマージしたいプロパティが含まれていますが、マージできませんでした。

QUERY1-私が望む結果を正確に与えてくれます。遅い(〜0.700秒)

クエリ2-無視してスキップする行がたくさん表示されます。高速(〜0.005秒)

私の目標は、QUERY 2を変更して、各アイテムの1を除くすべてのnull価格行を削除することです。パフォーマンスに影響を与えずにこれを行うことはできないようです。これは、MySQLでのインデックスの使用に関する経験と理解が不足しているためです。

QUERY 1

10k行を含むtbl_sale(e)全体でインデックスを使用できない、不適切に設計されたサブクエリを使用します。

SELECT b.id, b.sv, b.description, der.store_id, f.name, der.price
FROM tbl_watch AS a
    LEFT JOIN tbl_item AS b ON a.item_id = b.id
LEFT JOIN (
    SELECT c.store_id, d.flyer_id, e.item_id, e.price
    FROM tbl_storewatch AS c, tbl_storeflyer AS d
    FORCE INDEX ( storebeg_ndx ) , tbl_sale AS e
    WHERE c.user_id = '$user_id'
    AND (
        d.store_id = c.store_id
        AND d.date_beg = '20121206'
        )
    AND e.flyer_id = d.flyer_id
        ) AS der ON a.item_id = der.item_id
LEFT JOIN tbl_store as f ON der.store_id = f.id
WHERE a.user_id = '$user_id'
ORDER BY b.description ASC

これがQUERY1の説明です

id  select_type table       type    possible_keys   key             key_len     ref     rows    Extra
1   PRIMARY     a           ref     user_item_ndx   user_item_ndx   4           const   30  Using index; Using temporary; Using filesort
1   PRIMARY     b           eq_ref  PRIMARY         PRIMARY         4           a.item_id   1   
1   PRIMARY     <derived2>  ALL     NULL            NULL            NULL        NULL    300     
1   PRIMARY     f           eq_ref  PRIMARY         PRIMARY         4           der.store_id    1   
2   DERIVED     c           ref     user_ndx        user_ndx        4                   6   
2   DERIVED     e           ALL     NULL            NULL    NULL    NULL                9473    Using join buffer
2   DERIVED     d           eq_ref  storebeg_ndx    storebeg_ndx    8           c.store_id  1   Using where

QUERY 2

非常に効率的なすべての左結合を使用します(ORDER BYを除く)。インデックスはすべての結合で使用されます。このクエリは、tbl_watch内のすべてのアイテムに対して可能なすべての一致を返します。クエリは次のとおりです。

SELECT b.id, b.sv, b.description, c.store_id, f.name, e.price
FROM tbl_watch AS a
LEFT JOIN tbl_item AS b ON a.item_id = b.id
LEFT JOIN tbl_storewatch AS c ON c.user_id = '$user_id'
LEFT JOIN tbl_storeflyer AS d ON d.store_id = c.store_id
    AND d.date_beg = '$s_date'
LEFT JOIN tbl_sale AS e ON e.item_id = a.item_id
    AND e.flyer_id = d.flyer_id 
LEFT JOIN tbl_store as f ON d.store_id = f.id
WHERE a.user_id = '$user_id'
ORDER BY b.description ASC

クエリの説明は次のとおりです。

id  select_type     table   type    possible_keys           key             key_len     ref                     rows    Extra
1   SIMPLE          a       ref     user_item_ndx           user_item_ndx   4           const                   6       Using index; Using temporary; Using filesort
1   SIMPLE          b       eq_ref  PRIMARY                 PRIMARY         4           a.item_id               1   
1   SIMPLE          c       ref     user_ndx                user_ndx        4           const                   2   
1   SIMPLE          d       eq_ref  storebeg_ndx,storendx   storebeg_ndx    8           c.store_id,const        1   
1   SIMPLE          e       eq_ref  itemflyer_ndx           itemflyer_ndx   8           a.item_id,d.flyer_id    1   
1   SIMPLE          f       eq_ref  PRIMARY                 PRIMARY         4           d.store_id              1   

QUERY 2(より効率的)を変更して、QUERY 1のように必要な行だけを処理するにはどうすればよいですか?

ありがとうマイク

4

2 に答える 2

1

私はこのクエリがあなたが望むものを与えると思います:

select a.id, a.sv, a.description, c.id, c.name, b.price
  from 
    tbl_item a left outer join tbl_sale b on (a.id=b.item_id)
      left outer join tbl_storeflyer d on (b.flyer_id=d.flyer_id and d.date_beg = '20120801')
      left outer join tbl_store c on (d.store_id = c.id)
      left outer join tbl_storewatch x on (c.id = x.store_id)
      left outer join tbl_watch y on (a.id = y.item_id);

NULLが含まれていると、いくつかの左結合が発生する可能性があります。別の方法は、ユニオンを使用することです。これは、MySQLを使用した方が高速な場合があります。

 select a.id, a.sv, a.description, c.id as store_id, c.name, b.price
  from
    tbl_item a,
    tbl_sale b,
    tbl_storeflyer d,
    tbl_store c,
    tbl_storewatch x,
    tbl_watch y
  where
    a.id = b.item_id and
    b.flyer_id = d.flyer_id and
    d.store_id = c.id and
    c.id = x.store_id and
    a.id = y.item_id and
    d.date_beg = '20120801'
union
 select a.id, a.sv, a.description, null as store_id, null as name, null as price
  from
    tbl_item a
  where
    a.id not in (select b.item_id from tbl_sale b);

ユニオンの後半を「notin」サブクエリではなく左外部結合で遊ぶ場合があります。これは、MySQLのバージョンがどのように最適化されているかによって異なります。

于 2012-12-08T11:07:15.847 に答える
0

クエリ 1 のサブセレクトは暗黙的な内部結合を使用していますが、クエリ 2 はすべての左結合の明示的な結合を使用しています。したがって、クエリ 2 にはデータを除外する where 句はありません。LEFT を数行 (マークされているように) 取り出して、これがどのように改善されるかを確認します。

SELECT b.id, b.sv, b.description, c.store_id, f.name, e.price
FROM tbl_watch AS a
LEFT JOIN tbl_item AS b ON a.item_id = b.id
LEFT JOIN tbl_storewatch AS c ON c.user_id = '$user_id'
-- Left removed below
JOIN tbl_storeflyer AS d ON d.store_id = c.store_id
    AND d.date_beg = '$s_date'
-- Left removed below
JOIN tbl_sale AS e ON e.item_id = a.item_id
    AND e.flyer_id = d.flyer_id 
LEFT JOIN tbl_store as f ON d.store_id = f.id
WHERE a.user_id = '$user_id'
ORDER BY b.description ASC`

また、結合から and 句を取り出して、それらを WHERE に移動することを検討することもできます。

SELECT b.id, b.sv, b.description, c.store_id, f.name, e.price
FROM tbl_watch AS a
LEFT JOIN tbl_item AS b ON a.item_id = b.id
LEFT JOIN tbl_storewatch AS c ON c.user_id = '$user_id'
JOIN tbl_storeflyer AS d ON d.store_id = c.store_id
JOIN tbl_sale AS e ON e.item_id = a.item_id
LEFT JOIN tbl_store as f ON d.store_id = f.id
WHERE a.user_id = '$user_id'
AND d.date_beg = '$s_date'
AND e.flyer_id = d.flyer_id 
ORDER BY b.description ASC

最後に、日付計算はかなり集中的です。クエリ 2 では、外部結合を使用して多くのことを回避していますが、必要になる場合もあります。サブクエリを使用して ID を取得し、それによって制限しようとします。

SELECT b.id, b.sv, b.description, c.store_id, f.name, e.price
FROM tbl_watch AS a
LEFT JOIN tbl_item AS b ON a.item_id = b.id
LEFT JOIN tbl_storewatch AS c ON c.user_id = '$user_id'
JOIN tbl_storeflyer AS d ON d.store_id = c.store_id
JOIN tbl_sale AS e ON e.item_id = a.item_id
LEFT JOIN tbl_store as f ON d.store_id = f.id
WHERE a.user_id = '$user_id'
AND e.flyer_id = d.flyer_id 
AND d.id in  (select d.id from d where date_beg = '$s_date')
ORDER BY b.description ASC
于 2012-12-08T07:01:11.197 に答える