提问人:Asmor 提问时间:9/19/2008 最后编辑:TarynAsmor 更新时间:3/4/2016 访问量:27955
对 SQL 查询(特别是 MySQL)长度的实际限制
Practical limit to length of SQL query (specifically MySQL)
问:
有一个非常非常大的 SQL 查询,其中包含许多(可能是冗余的)WHERE 子句,这是否特别糟糕?
例如,下面是我从我的 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
它似乎运行良好,但它的流量也不是特别高(每天几百次点击左右),我想知道是否值得尝试优化查询以消除冗余等。
答:
大多数数据库都支持存储过程以避免此问题。如果您的代码执行速度足够快且易于阅读,则不必为了缩短编译时间而更改它。
另一种方法是使用预准备语句,以便每个客户端连接只获得一次命中,然后仅传入每个调用的参数
默认 MySQL 5.0 服务器限制为“1MB”,最多可配置为 1GB。
这是通过客户端和服务器上的max_allowed_packet设置配置的,有效限制是两者的出租人。
警告:
- 此“数据包”限制可能不会直接映射到 SQL 语句中的字符。当然,您希望考虑客户端中的字符编码、某些数据包元数据等。
阅读您的查询让我想玩角色扮演游戏。
这绝对不会太长。只要它们的格式正确,我会说实际限制是大约 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.
*/
评论
我假设你的意思是“关闭”一个字段没有值?
而不是检查某物是否不是这个,也不是那个等等,你不能检查字段是否为空吗?或者将字段设置为“off”,并检查 type 或其他内容是否等于“off”。
从实际的角度来看,我通常认为任何最终需要超过 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
这可能太大了;然而,优化在很大程度上取决于环境。
请记住,查询越长、越复杂,维护起来就越困难。
选择 @@global.max_allowed_packet
这是唯一真正的限制,它可以在服务器上调整,因此没有真正的直接答案
评论