【问题标题】:T-SQL 1=1 Performance HitT-SQL 1=1 性能下降
【发布时间】:2010-11-06 04:15:19
【问题描述】:

对于我的 SQL 查询,我通常对 SELECT 语句执行以下操作:

SELECT ...
FROM table t
WHERE 1=1
  AND t.[column1] = @param1
  AND t.[column2] = @param2

如果我需要添加/删除/注释任何 WHERE 子句,这将很容易,因为我不必关心第一行。

使用此模式时是否会影响性能?

其他信息:

绵羊模拟器和所有其他没有得到使用的示例。

假设上述查询,我​​需要将@param1 更改为不包含在查询中:

1=1:

...
WHERE 1=1 <-- no change
  --AND t.[column1] = @param1 <-- changed
  AND t.[column2] = @param2 <-- no change
...

没有 1=1:

...
WHERE <-- no change
  --t.[column1] = @param1 <-- changed
  {AND removed} t.[column2] = @param2 <-- changed
...

【问题讨论】:

  • 很抱歉,如果这听起来有点愚蠢,但我真的不确定在 WHERE 子句中添加 1=1 如何为您带来上述好处;您能为我们这些想了解这种可能的最佳实践的人详细说明一下吗?
  • @sheepsimulator:评论和取消评论任何条件都非常容易,只需在它前面加上双破折号 (--)
  • 嘿阿德里安,我总是做同样的事情,构建动态查询真是太舒服了......

标签: sql-server tsql


【解决方案1】:

如果您使用分析器并进行查看,您最终可能会发现优化器通常会忽略这一点,因此从总体上看,可能不会有太多性能增益或损失的方式。

【讨论】:

  • 我同意。 @Adrian- 如果将两个查询写在一起并打开执行计划,您可能会看到两个查询各占 50%。
【解决方案2】:

没有性能损失。即使你的 WHERE 子句加载了大量的比较,这也是很小的。

最好的情况是逐位比较。更糟糕的情况是数字被评估为整数。

【讨论】:

    【解决方案3】:

    不,SQL Server 足够聪明,可以从执行计划中省略这个条件,因为它总是TRUE

    Oracle、MySQL 和 PostgreSQL 也是如此。

    【讨论】:

    • 你有这个来源吗?我相信你,我只是链接一些东西来参考。
    • @Danny:对于 MySQL,是的:dev.mysql.com/doc/refman/5.6/en/where-optimizations.html 去除常量条件(因为常量折叠需要),对于其他人来说,常量折叠是任何优化器的核心特性
    【解决方案4】:

    对于任何合理复杂的查询都没有区别。您可以查看一些执行计划,也可以比较实际执行成本,然后自己看看。

    【讨论】:

      【解决方案5】:

      没有区别,因为它们评估了常量并进行了优化。我在手动和代码生成的ANDOR 列表中都使用了 1=1 和 0=1,但它没有任何效果。

      【讨论】:

        【解决方案6】:

        这对性能没有影响,但那里的 SQL 文本看起来像是被 SQL 注入攻击破坏了。 '1=1' 技巧出现在许多基于 sql 注入的攻击中。您只是冒着有一天您的某个客户部署了一个监视 SQL 流量的“黑匣子”的风险,您会发现您的应用程序被标记为“被黑”。源代码分析器也可能会标记这一点。当然,这是一个远大的目标,但值得平衡。

        【讨论】:

        • 一个很酷的技巧,但这是一个有效的观点。我可能会在开发过程中开始使用它,但我想在将其发布到生产环境之前将其取出。
        • 我想说的不是一个有效的观点。 SQL 注入使用“OR 1=1”而不是“1=1 AND”。这两者明显不同,如果一个应用无法区分它们,你确定其他结果可靠吗?
        • 如果您在 Web 应用程序或 SAAS 系统上执行此操作,客户可能无法安装自己的监控工具。当然,如果你自己安装,你知道这些查询是安全的。
        【解决方案7】:

        由于条件始终为真,SQL Server 将忽略它。您可以通过运行两个查询来检查,一个有条件,一个没有条件,然后比较两个实际的执行计划。

        实现易于评论要求的另一种方法是重组您的查询:

        SELECT ...
        FROM table t
        WHERE 
            t.[column1] = @param1 AND
            t.[column2] = @param2 AND
            t.[column3] = @param3
        

        然后您可以在 where 条件中添加/删除/注释掉行,它仍然是有效的 SQL。

        【讨论】:

        • 添加一行需要修改最后一行。
        • 同时注释最后一行需要修改倒数第二行。
        【解决方案8】:

        其中一个潜在的轻微负面影响是 AND 1=1 将阻止 SQL Server 的 simple parameterisation 设施启动。

        演示脚本

        DBCC FREEPROCCACHE;  /*<-- Don't run on production box!*/
        
        CREATE TABLE [E7ED0174-9820-4B29-BCDF-C999CA319131]
        (
        X INT, 
        Y INT,
        PRIMARY KEY (X,Y)
        );
        
        GO
        SELECT *
        FROM   [E7ED0174-9820-4B29-BCDF-C999CA319131]
        WHERE  X = 1
               AND Y = 2;
        GO
        SELECT *
        FROM   [E7ED0174-9820-4B29-BCDF-C999CA319131]
        WHERE  X = 2
               AND Y = 3;
        GO   
        SELECT *
        FROM   [E7ED0174-9820-4B29-BCDF-C999CA319131]
        WHERE  1 = 1
               AND X = 1
               AND Y = 2 
        GO   
        SELECT *
        FROM   [E7ED0174-9820-4B29-BCDF-C999CA319131]
        WHERE  1 = 1
               AND X = 2
               AND Y = 3    
        

        SELECT usecounts,
               execution_count,
               size_in_bytes,
               cacheobjtype,
               objtype,
               text,
               creation_time,
               last_execution_time,
               execution_count
        FROM   sys.dm_exec_cached_plans a
               INNER JOIN sys.dm_exec_query_stats b
                 ON a.plan_handle = b.plan_handle
               CROSS apply sys.dm_exec_sql_text(b.sql_handle) AS sql_text
        WHERE  text LIKE '%\[E7ED0174-9820-4B29-BCDF-C999CA319131\]%' ESCAPE '\'
               AND text NOT LIKE '%this_query%'
        ORDER BY last_execution_time DESC       
        
        GO
        
        DROP TABLE [E7ED0174-9820-4B29-BCDF-C999CA319131]   
        

        表明没有1=1 的查询都被缓存计划的单个参数化版本满足,而带有1=1 的查询为不同的常量值编译并存储了一个单独的计划。

        理想情况下,无论如何您都不应该依赖它,而应该显式参数化查询,以确保所需元素已参数化并且参数具有正确的数据类型。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-08-22
          • 1970-01-01
          • 2017-04-15
          • 1970-01-01
          • 1970-01-01
          • 2012-07-02
          • 1970-01-01
          • 2016-03-12
          相关资源
          最近更新 更多