3

私は小さな問題に遭遇しています、

これはデモクエリです

select 
    A.order_id, 
    if(
         A.production_date != '0000-00-00', 
         A.production_date,
         if(
              SOME INNER QUERY != '0000-00-00', 
              SOME INNER QUERY ,
              SOME OTHER INNER QUERY
           )
    ) as production_start_date
from
    orders A

基本的に、SOME INNER QUERYが計算を行うのに 10 秒かかり、8 つの異なるテーブルからデータをフェッチし、同じ注文タイプの過去の履歴をチェックするとします。結果が日付の場合、最初の条件でその日付をフェッチします。ただし、if 条件の計算に 10 秒、結果を返すための再実行に 10 秒かかるため、20 秒かかります。

これを減らす方法はありますか?

実際のクエリを見ることに興味がある人はhttp://pastebin.com/zqzbpEei

4

1 に答える 1

1

クエリが次のようになっていると仮定します (申し訳ありませんが、実際のクエリを見つけるのをあきらめました)。

IF(
    (SELECT aField FROM aTable WHERE bigCondition) != '0000-00-00',
    SELECT aField FROM aTable WHERE bigCondition,
    SELECT anotherField FROM anotherTable
)

次のように書き換えることができます。

SELECT IF (
    someField != '0000-00-00',
    someField,
    SELECT anotherField FROM anotherTable
)
FROM aTable WHERE bigCondition

この方法では、一度だけ計算しますbigCondition


このクエリは実に醜いです。

あなたの主な問題は、構造の誤用(および乱用、大きな時間)のようIF()です。単純な条件と操作に限定する必要があります。同じことが論理演算子にも当てはまります。クエリ全体を操作しないでください。たとえば、次の 1 つのビットがクエリに数回表示されます。

IF(
    (SELECT v1.weekends FROM vendor v1 WHERE v1.vendor_id = A.vendor_id) IS NULL
       OR (SELECT v1.weekends FROM vendor v1 WHERE v1.vendor_id = A.vendor_id) = '',
    '6', -- by the way, why is this a string?! This is an integer, isn't it?
    (SELECT v1.weekends FROM vendor v1 WHERE v1.vendor_id = A.vendor_id)
)

これは悪いです。条件はSELECT直接に移動する必要があります。以下のように書き換えます。

SELECT
    IF (v1.weekends IS NULL OR v1.weekends = '', 6, v1.weekends)
FROM vendor v1 WHERE v1.vendor_id = A.vendor_id

これで2人SELECT救われました。クエリを含むすべてIF()のクエリに対してこれを実行すると、クエリが数桁高速化されることは間違いありません。

現在のコードについては、さらに多くのことが言えます。残念ながら、おそらく ORM の一部をリファクタリングする必要があります。一部のクラスに、より特化した新しいメソッドを追加し、手動で作成した新しいクエリを使用するようにします。次に、現在の操作をリファクタリングして、これらの新しいメソッドを使用するようにします。

于 2013-07-25T21:32:11.497 に答える