【问题标题】:Practical limit to length of SQL query (specifically MySQL)SQL 查询长度的实际限制(特别是 MySQL)
【发布时间】:2010-09-10 22:13:48
【问题描述】:

拥有大量(可能是冗余的)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.感谢您回答问题,我认为查询的大小现在对我来说应该不是问题。 2.谢谢大家对格式化SQL的提示。我是新手,有很多我不知道的技巧(例如“不输入(...)”) 3. 作为附录,这是一个 PHP/MySQL 应用程序
  • 这是一个有用的在线 SQL 格式化程序:sqlinform.com

标签: mysql sql optimization


【解决方案1】:

大多数数据库都支持存储过程来避免这个问题。如果您的代码执行速度足够快且易于阅读,您就不必为了缩短编译时间而对其进行更改。

另一种方法是使用准备好的语句,这样每个客户端连接只获得一次命中,然后只传递每个调用的参数

【讨论】:

    【解决方案2】:

    默认 MySQL 5.0 服务器限制为“1MB”,最高可配置为 1GB。

    这是通过客户端和服务器上的max_allowed_packet设置来配置的,有效的限制是两者的出租者。

    注意事项:

    • 这种“数据包”限制可能不会直接映射到 SQL 语句中的字符。当然,您需要考虑客户端中的字符编码、一些数据包元数据等)

    【讨论】:

      【解决方案3】:

      阅读您的查询让我想玩 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.
      */
      

      【讨论】:

      • 实际上加入会加快速度,尤其是使用适当的索引。原因是如果你的所有子句都在 WHERE 中,mysql 会获取所有数据,然后过滤它;而通过适当的连接,它将仅选择所需的数据,这些数据可以小几个数量级 - 过滤速度更快。
      • 哦,而且...除非我遗漏了什么, (type!='Armor' OR (false)) 将评估为真或假,但在任何一种情况下都不是会影响结果集,所以真的不需要。
      • 这是因为盔甲(和武器)按类型进一步过滤。因此,例如,如果选择了 Cloth 和 Hide,则显示为: (type!='Armor' OR (FALSE OR 限制,如 'C' OR 限制,如 'H')) 页面只添加“或限制,如 'whatever' " 在括号内,所以需要 false 。
      • FROM 子句中的连接将使您的 WHERE 子句变得整洁。 @Aeon - 使用适当的查询优化器应该没有性能差异。 mysql有那么差吗?
      • 反对将 WHERE 子句与 JOIN 条件混淆。
      【解决方案4】:

      我假设您所说的“关闭”是指字段没有值?

      而不是检查某些东西是否不是这个,它也不是那个等等。你不能只检查该字段是否为空吗?或者将该字段设置为“关闭”,并检查类型或其他内容是否等于“关闭”。

      【讨论】:

        【解决方案5】:

        从实际的角度来看,我通常认为任何最终花费超过 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
        

        这可能太大了;然而,优化很大程度上取决于上下文。

        请记住,查询越长越复杂,维护起来就越困难。

        【讨论】:

          【解决方案6】:

          选择@@global.max_allowed_pa​​cket

          这是它在服务器上唯一可以调整的真正限制,因此没有真正的直接答案

          【讨论】:

            猜你喜欢
            • 2019-12-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-12-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-07-20
            相关资源
            最近更新 更多