实际限制SQL查询的长度(特别是MySQL)
拥有很多(可能是冗余的)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
它似乎工作得很好,但是流量也不是特别高(每天点击几百次),我想知道是否值得尝试优化查询以消除冗余等。
解决方案
大多数数据库都支持存储过程来避免此问题。如果代码执行起来足够快并且易于阅读,那么我们就不必为了缩短编译时间而对其进行更改。
一种替代方法是使用准备好的语句,这样我们每次客户端连接仅获得一次匹配,然后仅为每个调用传递参数
默认的MySQL 5.0服务器限制为" 1MB",最多可配置1GB。
这是通过客户端和服务器上的max_allowed_packet设置配置的,有效限制是两者中的较小者。
注意事项:
- 此"数据包"限制可能不会直接映射到SQL语句中的字符。当然,我们要考虑客户端中的字符编码,某些数据包元数据等)
阅读查询使我想玩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. */
我假设意思是"关闭"字段没有值?
而不是检查是否不是某些东西,也不是那样,等等。我们不能仅检查字段是否为空吗?或者将字段设置为" off",然后检查类型是否等于" off"。
从实际的角度来看,我通常认为任何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
这可能太大了;然而,优化将在很大程度上取决于上下文。
请记住,查询越长越复杂,维护起来就越困难。