17

大量の (潜在的に冗長な) WHERE 句を含む非常に大きな SQL クエリを使用することは特に悪いことですか?

たとえば、すべてをオフにして Web アプリケーションから生成したクエリを次に示します。これは、このプログラムが生成できる最大のクエリになるはずです。

SELECT * 
FROM 4e_magic_items 
INNER JOIN 4e_magic_item_levels 
  ON 4e_magic_items.id = 4e_magic_item_levels.itemid 
INNER JOIN 4e_monster_sources 
  ON 4e_magic_items.source = 4e_monster_sources.id 
WHERE (itemlevel BETWEEN 1 AND 30)  
  AND source!=16 AND source!=2 AND source!=5 
  AND source!=13 AND source!=15 AND source!=3 
  AND source!=4 AND source!=12 AND source!=7 
  AND source!=14 AND source!=11 AND source!=10 
  AND source!=8 AND source!=1 AND source!=6 
  AND source!=9  AND type!='Arms' AND type!='Feet' 
  AND type!='Hands' AND type!='Head' 
  AND type!='Neck' AND type!='Orb' 
  AND type!='Potion' AND type!='Ring' 
  AND type!='Rod' AND type!='Staff' 
  AND type!='Symbol' AND type!='Waist' 
  AND type!='Wand' AND type!='Wondrous Item' 
  AND type!='Alchemical Item' AND type!='Elixir' 
  AND type!='Reagent' AND type!='Whetstone' 
  AND type!='Other Consumable' AND type!='Companion' 
  AND type!='Mount' AND (type!='Armor' OR (false )) 
  AND (type!='Weapon' OR (false )) 
 ORDER BY type ASC, itemlevel ASC, name ASC

十分に機能しているように見えますが、特にトラフィックが多いわけでもありません (1 日に数百ヒット程度)。クエリを最適化して冗長性などを取り除く努力をする価値があるかどうか疑問に思います。

4

6 に答える 6

20

あなたの質問を読むと、RPGをプレイしたくなります。

これは間違いなく長すぎません。うまくフォーマットされている限り、実際の制限は約100行だと思います。その後は、目を交差させないようにするために、サブクエリをビューに分割することをお勧めします。

1000行以上のクエリをいくつか処理しましたが、デバッグが困難です。

ちなみに、再フォーマット版を提案してもいいですか?これは主に、フォーマットの重要性を示すためです。これが理解しやすいと思います。

select *  
from
  4e_magic_items mi
 ,4e_magic_item_levels mil
 ,4e_monster_sources ms
where mi.id = mil.itemid
  and mi.source = ms.id
  and itemlevel between 1 and 30
  and source not in(16,2,5,13,15,3,4,12,7,14,11,10,8,1,6,9)  
  and type not in(
                  'Arms' ,'Feet' ,'Hands' ,'Head' ,'Neck' ,'Orb' ,
                  'Potion' ,'Ring' ,'Rod' ,'Staff' ,'Symbol' ,'Waist' ,
                  'Wand' ,'Wondrous Item' ,'Alchemical Item' ,'Elixir' ,
                  'Reagent' ,'Whetstone' ,'Other Consumable' ,'Companion' ,
                  'Mount'
                 )
  and ((type != 'Armor') or (false))
  and ((type != 'Weapon') or (false))
order by
  type asc
 ,itemlevel asc
 ,name asc

/*
Some thoughts:
==============
0 - Formatting really matters, in SQL even more than most languages.
1 - consider selecting only the columns you need, not "*"
2 - use of table aliases makes it short & clear ("MI", "MIL" in my example)
3 - joins in the WHERE clause will un-clutter your FROM clause
4 - use NOT IN for long lists
5 - logically, the last two lines can be added to the "type not in" section.
    I'm not sure why you have the "or false", but I'll assume some good reason
    and leave them here.
*/
于 2008-09-18T20:32:38.653 に答える
18

デフォルトの MySQL 5.0 サーバーの制限は " 1MB " で、最大 1GB まで構成可能です。

これは、クライアントとサーバーの両方でmax_allowed_pa​​cket設定を介して構成され、有効な制限は 2 つのうち小さい方です。

警告:

  • この「パケット」の制限は、SQL ステートメントの文字に直接マップされない可能性があります。確かに、クライアント内の文字エンコーディング、一部のパケット メタデータなどを考慮に入れる必要があります。)
于 2008-09-18T20:32:16.640 に答える
3

@@global.max_allowed_pa​​cket を選択

これはサーバー上で調整できる唯一の実際の制限であるため、本当の直接的な答えはありません

于 2016-03-04T08:49:44.467 に答える
1

実用的な観点から、私は通常、書くのに 10 行以上かかる (各句/条件を別の行に入れる) SELECT は長すぎて簡単に保守できないと考えています。この時点で、おそらく何らかのストアド プロシージャとして実行する必要があります。または、同じ概念を表現するためのより良い方法を見つけようとする必要があります。

あなたのマイレージは異なる場合があり、正当な理由がある非常に長いクエリがいくつかあります. しかし、私の経験則は10行です。

(少し不適切な SQL):

SELECT x, y, z
FROM a, b
WHERE fiz = 1
AND foo = 2
AND a.x = b.y
AND b.z IN (SELECT q, r, s, t
            FROM c, d, e
            WHERE c.q = d.r
              AND d.s = e.t
              AND c.gar IS NOT NULL)
ORDER BY b.gonk

これはおそらく大きすぎます。ただし、最適化はコンテキストに大きく依存します。

覚えておいてほしいのは、クエリが長く複雑になればなるほど、維持するのが難しくなるということです。

于 2008-09-18T20:39:23.067 に答える
0

「オフ」とは、フィールドに値がないことを意味していると思いますか?

何かがこれではないかどうかをチェックする代わりに、それもそうではないなど、フィールドがnullであるかどうかをチェックすることはできませんか?または、フィールドを「オフ」に設定し、タイプまたは「オフ」に等しいものがあるかどうかを確認します。

于 2008-09-18T20:34:39.850 に答える
0

ほとんどのデータベースは、この問題を回避するためにストアド プロシージャをサポートしています。コードが実行するのに十分高速で読みやすい場合は、コンパイル時間を短縮するためにコードを変更する必要はありません。

別の方法は、準備済みステートメントを使用して、クライアント接続ごとに 1 回だけヒットを取得し、各呼び出しのパラメーターのみを渡すことです。

于 2008-09-18T20:30:20.030 に答える