如何优化此查询(或内部 AND 验证)?

Posted

技术标签:

【中文标题】如何优化此查询(或内部 AND 验证)?【英文标题】:How Can I optimize this query (OR inside AND validation)? 【发布时间】:2011-11-29 19:25:20 【问题描述】:

我遇到了这个查询的问题:

SELECT col1, col2,col3,...,coln FROM MyTable
WHERE col1 = @value1
AND
(
ISNULL(col2,'c') = ISNULL(@value2,ISNULL(col2,'c'))
OR
ISNULL(col3,'c') = ISNULL(@value2,ISNULL(col3,'c'))
)
 AND coln = 'valueN'

我必须停止执行,太慢了。但编辑:

SELECT col1, col2,col3,...,coln FROM MyTable
WHERE col1 = @value1
AND
(
ISNULL(col2,'c') = ISNULL(@value2,ISNULL(col2,'c'))
)
AND coln = 'valueN'

这个查询速度更快。有人能帮我吗?如何替换 or 语句或替换查询但验证 col1 和 col2?。 谢谢。

更新:

非常感谢你们。真的,我的查询不使用'=',而是使用'Like',对此感到抱歉。但是,我使用您的建议来构建我的查询并且效果很好:

SELECT col1, col2,col3,...,coln FROM MyTable
WHERE col1 like '%' + @value1 + '%'
AND
(
 (@value2 IS NULL)
 OR
  (col2 IS NOT NULL AND col2 LIKE '%' + @value2 + '%')
 OR
 (col3 IS NOT NULL AND col3 LIKE '%' + @value2 + '%')
)
 AND coln = 'valueN'

我将此查询与一个页面一起使用,其中我有许多字段来过滤搜索,并且我需要一个 col2 文本框也适用于数据库中的 col3,我的意思是,数据库中只有一个用于 name1 和 name2 的文本框。

对不起,我的错误问题,感谢您的建议。

【问题讨论】:

您能否根据 value2 是否为空来更改参数化查询?坏情况的查询计划有什么明显的地方吗? 感谢您的回答。 Adrian 解决方案工作正常,查询必须验证必要的,而不是像我总是验证的旧查询。 【参考方案1】:
ISNULL(col2,'c') = ISNULL('value2',ISNULL(col2,'c'))

一样
col2 = 'value2' or (col2 is null and 'value2' is null)

替换出现的次数,您很可能会获得更好的性能。

更新

此解决方案与@onedaywhen 提出的解决方案有一个根本区别:当'value2' 中提供的值(我想这只是一个组装成SQL 字符串的参数)是NULL 时,OP 只想带仅返回 col2 为 NULL 的记录。仔细看看 OP 的逻辑,你会在那里看到。 OP的逻辑总是过滤:当参数为NULL时,OP想要col2 is NULL的记录。

@onedaywhen 的解决方案在参数为NULL 时带来every 记录。虽然这是一个非常常见的查询,但这不是 OP 正在寻找的

【讨论】:

工作正常!!。非常感谢。 您的断言(“相同”)是错误的。考虑ISNULL('value2',ISNULL(col2,'c')) 将始终评估为“value2”。 ...即使您将'value2' 更正为@value2,您的建议也不等同于OP! @onedaywhen 我同意value2 应该是@value2。也就是说,仔细查看 OP 的逻辑,您会看到 OP 的要求:查询将始终过滤!如果参数为 NULL,OP 只想带 col2 为 NULL 的记录,不是每条记录。 你同意如果列和参数值都为空,那么ISNULL逻辑会认为它们都是c吗?这有效地改变了 SQL 的 3VL 逻辑,以便NULL = NULL 为该谓词计算 TRUE。请参阅我的更新答案以进行演示:)【参考方案2】:
ISNULL(col2,'c') = ISNULL(@value2,ISNULL(col2,'c'))

一样
( ( col2 = @value2 ) OR ( @value2 IS NULL ) ) 

但我不确定这是否会提高性能:我已经阅读过 to get an efficient, scalable and performant solution either use IF ELSE control of flow blocks (one per parameter combination) or use dynamic SQL,至少对于 SQL Server 2005 及更早版本。


更新:...这是证据:


查询一:当参数为非空值时:

DECLARE @value2 VARCHAR(10);
SET @value2 = 'Apples';
WITH T 
     AS 
     (
      SELECT * 
        FROM (
              VALUES (1, 'When col2 is null', NULL), 
                     (2, 'When col2 is the same value as @value2', 'Apples'), 
                     (3, 'When col2 is not the same value as @value2', 'Oranges')
             ) AS T (ID, narrative, col2)
     )
SELECT *, 
       CASE WHEN ISNULL(col2,'c') = ISNULL(@value2,ISNULL(col2,'c')) THEN 'T' END AS OP, 
       CASE WHEN ( ( col2 = @value2 ) OR ( @value2 IS NULL ) ) THEN 'T' END AS OneDayWhen, 
       CASE WHEN col2 = @value2 or (col2 is null and @value2 is null) THEN 'T' END AS Adrian
  FROM T;

输出 1:

ID          narrative                                  col2    OP   OneDayWhen Adrian
----------- ------------------------------------------ ------- ---- ---------- ------
1           When col2 is null                          NULL    NULL NULL       NULL
2           When col2 is the same value as @value2     Apples  T    T          T
3           When col2 is not the same value as @value2 Oranges NULL NULL       NULL

注意所有行都同意:)


查询2:当参数为空时:

DECLARE @value2 VARCHAR(10);
SET @value2 = NULL;
WITH T 
     AS 
     (
      SELECT * 
        FROM (
              VALUES (1, 'When col2 is null', NULL), 
                     (2, 'When col2 is the same value as @value2', 'Apples'), 
                     (3, 'When col2 is not the same value as @value2', 'Oranges')
             ) AS T (ID, narrative, col2)
     )
SELECT *, 
       CASE WHEN ISNULL(col2,'c') = ISNULL(@value2,ISNULL(col2,'c')) THEN 'T' END AS OP, 
       CASE WHEN ( ( col2 = @value2 ) OR ( @value2 IS NULL ) ) THEN 'T' END AS OneDayWhen, 
       CASE WHEN col2 = @value2 or (col2 is null and @value2 is null) THEN 'T' END AS Adrian
  FROM T;

输出 2:

ID          narrative                                  col2    OP   OneDayWhen Adrian
----------- ------------------------------------------ ------- ---- ---------- ------
1           When col2 is null                          NULL    T    T          T
2           When col2 is the same value as @value2     Apples  T    T          NULL
3           When col2 is not the same value as @value2 Oranges T    T          NULL

注意 OP 和 OneDayWhen 匹配所有行,Adrian 仅匹配行 ID = 1。

【讨论】:

你是对的。但我敢打赌,OP 想要 Adrian 的逻辑。 @ypercube:我会接受这个赌注;) @ypercube 请花点时间阅读我的答案更新。谢谢

以上是关于如何优化此查询(或内部 AND 验证)?的主要内容,如果未能解决你的问题,请参考以下文章

如何测试数据库查询优化器

如何使用 Join 优化查询

编写快速 MySQL INSERT 查询或优化此查询

MySQL 基础模块的面试题

如何针对 Oracle 优化此查询

如何优化此查询