Особенно плохо иметь очень, очень большой SQL-запрос с большим количеством (потенциально избыточных) пунктов WHERE?
Например, вот запрос, который я сгенерировал из моего веб-приложения с выключенными параметрами, что должно быть самым большим возможным запросом для этой программы:
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
Кажется, что все работает достаточно хорошо, но трафик не очень большой (несколько сотен просмотров в день или около того), и я думаю, стоит ли пытаться оптимизировать запросы, чтобы убрать избыточность и тому подобное.
Читая ваш запрос, я хочу сыграть в ролевую игру.
Это определенно не слишком длинно. Если они хорошо отформатированы, я бы сказал, что практический предел - около 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.
*/
Ограничение сервера MySQL 5.0 по умолчанию составляет "1MB", настраиваемое до 1GB.
Это настраивается с помощью параметра max_allowed_packet как на клиенте, так и на сервере, и эффективным ограничением является меньшее из двух.
Предостережения:
С практической точки зрения, я вообще считаю любой выбор, который заканчивает брать более 10 строк писать (каждый пункт/условие на отдельной строке), чтобы быть слишком долго, чтобы легко поддерживать. На данный момент, это должно, вероятно, быть сделано как хранимая процедура какая-то, или я должен попытаться найти эффективный способ, чтобы выразить то же понятие, возможно, путем создания промежуточной таблицы, чтобы захватить некоторые отношения мне кажутся часто запрос.
Ваш пробег может варьироваться, и есть некоторые очень длинные запросы, которые имеют все основания быть. Но мое правило-это 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
Это, пожалуй, слишком большие, оптимизацию, однако, будет во многом зависеть от контекста.
Просто помните, чем дольше и чем сложнее запрос, тем сложнее's будет поддерживать.
Большинство баз данных поддерживают хранимые процедуры, чтобы избежать этой проблемы. Если ваш код достаточно быстро выполняется и легко читается, вы не захотите менять его, чтобы уменьшить время компиляции.
В качестве альтернативы можно использовать подготовленные операторы, чтобы получать удар только один раз на каждое клиентское соединение, а затем передавать только параметры для каждого вызова.
Я'м предполагая, что вы имеете в виду под 'выключен' что поле не'т иметь значение?
Вместо того, чтобы проверить, если что-то не так, и это'ы и т. д. может'т вы просто проверить, если поле имеет значение null? Или установить поле 'выкл', и проверить, если тип или все равно 'выкл'.