Практическое ограничение длины SQL-запроса (в частности, MySQL) - PullRequest
17 голосов
/ 19 сентября 2008

Особенно плохо иметь очень, очень большой 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

Кажется, что он работает достаточно хорошо, но он также не особенно интенсивен (несколько сотен обращений в день или около того), и мне интересно, стоит ли пытаться оптимизировать запросы для устранения избыточности и тому подобного.

Ответы [ 6 ]

19 голосов
/ 19 сентября 2008

При чтении вашего запроса я хочу сыграть в 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.
*/
17 голосов
/ 19 сентября 2008

Ограничение сервера MySQL 5.0 по умолчанию: « 1MB », настраивается до 1 ГБ.

Это настраивается с помощью параметра max_allowed_packet как на клиенте, так и на сервере, и действующим ограничением является арендодатель обоих.

Предостережения:

  • Вполне вероятно, что это "пакетное" ограничение не отображается непосредственно на символы в выражении SQL. Конечно, вы хотите принять во внимание кодировку символов в клиенте, некоторые метаданные пакета и т. Д.)
3 голосов
/ 04 марта 2016

SELECT @@ global.max_allowed_packet

это единственное реальное ограничение, которое настраивается на сервере, поэтому нет прямого прямого ответа

1 голос
/ 19 сентября 2008

С практической точки зрения я обычно считаю, что любой SELECT, для написания которого требуется более 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

Это, вероятно, слишком большой; однако оптимизация во многом будет зависеть от контекста.

Помните, чем длиннее и сложнее запрос, тем сложнее его обслуживать.

0 голосов
/ 19 сентября 2008

Я предполагаю, что вы подразумеваете под 'выключено', что поле не имеет значения?

Вместо того, чтобы проверять, не является ли это чем-то, и это также не так и т.д., вы не можете просто проверить, является ли поле пустым? Или установите для поля значение «off» и проверьте, соответствует ли тип или «off».

0 голосов
/ 19 сентября 2008

Большинство баз данных поддерживают хранимые процедуры, чтобы избежать этой проблемы. Если ваш код достаточно быстр для выполнения и легко читается, вам не нужно менять его, чтобы сократить время компиляции.

В качестве альтернативы можно использовать подготовленные операторы, чтобы получить совпадение только один раз для каждого клиентского соединения, а затем передавать только параметры для каждого вызова

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...