我有SQL查询:
SELECT ISNULL(t.column1, t.column2) as [result]
FROM t
我需要按[result]列过滤掉数据。关于绩效的最佳方法是什么,如下所列:
WHERE ISNULL(t.column1, t.column2) = @filterValue
或:
WHERE t.column1 = @filterValue OR t.column2 = @filterValue
更新:对不起,我忘了提到如果column1已填满,column2始终为null。
答案 0 :(得分:5)
测量,不要猜!这是你应该自己做的事情,有类似生产的数据。 我们不知道您的数据的构成,这会产生很大的不同。
话虽如此,我不会这样做。如果非NULL,我会创建另一列column3
来存储column1
,如果column2
为NULL,我会创建column1
。
然后我会有一个插入/更新触发器来正确填充该列,将其编入索引并使用screaming-banshee-speed:
select t.column3 as [result] from t
浩大的大多数数据库的读取频率高于写入数据,如果这种计算尽可能少地完成(即数据发生变化时,而不是每次选择数据时)都会更好。如果您希望数据库可伸缩,请不要使用每行函数。
牺牲磁盘空间的速度是完全有效的,并且触发器确保数据不会变得不一致。
如果添加另一个列和触发器是不可能的,我会选择or
解决方案,因为它通常可以被更智能的DBMS引擎拆分为两个并行查询。
一个替代方案,MarkB给了但是因为删除了他的答案所以我将不得不去寻找他的另一个他的upvote :-)的好答案,就是使用UNION ALL
。如果您的DBMS不够聪明,无法将OR
视为并行机会,那么在该上下文中识别UNION ALL
可能足够聪明,例如:
select column1 as c from t where column1 is not NULL
union all
select column2 as c from t where column1 is NULL
但同样,这取决于您的数据库和数据。智能DBA会将整个事情放在存储过程中,这样如果数据更改其属性,它们就可以无缝地交换新方法。
答案 1 :(得分:1)
在MSSQL-Table(MSSQL 2000)上,在Col1和Col2上有13.000.000个条目和索引,我得到以下结果:
select top 1000000 * from Table1 with(nolock) where isnull(Col1,Col2) > '0'
-- Compile-Time: 4ms
-- CPU-Time: 18265ms
-- Elapsed-Time: 24882ms = ~25s
select top 1000000 * from Table1 with(nolock) where Col1 > '0' or (Col1 is null and Col2 > '0')
-- Compile-Time: 9ms
-- CPU-Time: 7781ms
-- Elapsed-Time: 25734 = ~26s
根据服务器的工作量,测量值会受到强烈波动的影响。
第一个语句需要较少的编译时间,但需要更多的cpu时间来执行(culstered index scan)。
重要的是要知道许多存储引擎都有一个优化器,它会重新组织声明以获得更好的结果和执行时间。最终,两个语句将由优化器重建为大致相同的语句。
答案 2 :(得分:0)
我认为,你的替代表达方式并不一样。假设filterValue为2
,则ISNULL(1,2)=2
为false,但1=2 or 2=2
为真。你需要的表达看起来更像是:
(c1=filter) or ((c1 is null) and (c2 = filter));
服务器有可能通过c1
上的索引回答这个问题。灵魂的第一部分是对c1=filter
的索引扫描。第二部分是对c1=null
的扫描,然后是c2=filter
的线性搜索。我甚至会说聚集索引(c1,c2)
可以在这里工作。
ISNULL(X,Y)
可以被分解为一个布尔语句及其对搜索的影响,但我不会依赖它,而是测量然后决定做什么。
答案 3 :(得分:0)
我已经在SQL Sever 2008上测量了两个查询的性能。
并得到以下结果:
这两种方法都具有几乎相同的估算的子树成本指标。 但 OR 方法具有更准确的估计行数指标值。
因此,查询优化器将为 OR 构建比 ISNULL 方法更合适的执行计划。