有没有更有效的方法来在这个特定的上下文中编写我的过滤器?
Is there a more efficient way to write my filters in this specific context?
我正在使用 SQL Server 2014
,我的数据库中有一个 table (t1
),其中包含一个数字列表(n1 到 n6)。摘录如下:
Id n1 n2 n3 n4 n5 n6
100 3 10 26 31 35 39
101 1 3 11 22 36 40
102 10 19 20 30 39 40
103 6 12 25 27 28 33
...
假设我想通过排除存在数字 3 和 19 的行来过滤掉此 table,我的过滤代码将如下所示:
Select * from t1
WHERE [n1] not in (3,19)
AND [n2] not in (3,19)
AND [n3] not in (3,19)
AND [n4] not in (3,19)
AND [n5] not in (3,19)
AND [n6] not in (3,19)
预期输出:
Id n1 n2 n3 n4 n5 n6
103 6 12 25 27 28 33
...
有没有更有效的方法来编写我的过滤器?
您的过滤器很好,但您可能会发现写成这样更简单:
where 3 not in (n1, n2, n3, n4, n5, n6) and
19 not in (n1, n2, n3, n4, n5, n6)
因为您引用的所有六列都不等式,所以您无法真正提高性能。您可以修复数据模型,使列位于不同的行中——允许使用索引。
一个选项使用 not exists
和 values()
:
select t.*
from mytable t
where not exists (
select 1
from (values(n1), (n2), (n3), (n4), (n5), (n6)) x(n)
where n in (3, 19)
)
当列表中的列数 and/or 值增加时,这比您的原始查询更好地缩放 - 尽管这不一定更有效。
Id | n1 | n2 | n3 | n4 | n5 | n6
--: | -: | -: | -: | -: | -: | -:
103 | 6 | 12 | 25 | 27 | 28 | 33
将一组不需要的值放在 CTE 中并使用 Except 运算符
正如其他人所指出的,数据模型并不理想。
要解决 NOT IN
过滤器的低效问题,您可以像这样使用 EXCEPT 运算符:
--sample data
WITH smple ( id, n1, n2, n3, n4, n5, n6) AS
( SELECT 100, 3, 10, 26, 31, 35, 39
union all
select 101,1,3,11,22,36,40
union all
select
102,10,19,20,30,39,40
union all
select
103,6,12,25,27,28,33
),
--end sample data
not_vals (n) as (select 3 union all select 19 )
SELECT
s.*
FROM
smple s
EXCEPT
SELECT
s.*
FROM
smple s join not_vals nv on
nv.n IN ( s.n1, s.n2, s.n3, s.n4, s.n5, s.n6)
;
从性能的角度看一下可以使用的各种方法的效率会很有趣。
最终解决方案应该具有良好的性能,因此相关子查询可能无法提供。
这是一个相关子查询:
--sample data
with smple ( id, n1, n2, n3, n4, n5, n6) AS
( SELECT 100, 3, 10, 26, 31, 35, 39
union all
select 101,1,3,11,22,36,40
union all
select
102,10,19,20,30,39,40
union all
select
103,6,12,25,27,28,33
),
--end sample data
not_vals (n) as (select 3 union all select 19 )
SELECT
s.*
FROM
smple s
WHERE
NOT EXISTS (
SELECT 1 FROM not_vals nv
WHERE
nv.n IN ( s.n1, s.n2, s.n3, s.n4, s.n5, s.n6)
)
;
我正在使用 SQL Server 2014
,我的数据库中有一个 table (t1
),其中包含一个数字列表(n1 到 n6)。摘录如下:
Id n1 n2 n3 n4 n5 n6
100 3 10 26 31 35 39
101 1 3 11 22 36 40
102 10 19 20 30 39 40
103 6 12 25 27 28 33
...
假设我想通过排除存在数字 3 和 19 的行来过滤掉此 table,我的过滤代码将如下所示:
Select * from t1
WHERE [n1] not in (3,19)
AND [n2] not in (3,19)
AND [n3] not in (3,19)
AND [n4] not in (3,19)
AND [n5] not in (3,19)
AND [n6] not in (3,19)
预期输出:
Id n1 n2 n3 n4 n5 n6
103 6 12 25 27 28 33
...
有没有更有效的方法来编写我的过滤器?
您的过滤器很好,但您可能会发现写成这样更简单:
where 3 not in (n1, n2, n3, n4, n5, n6) and
19 not in (n1, n2, n3, n4, n5, n6)
因为您引用的所有六列都不等式,所以您无法真正提高性能。您可以修复数据模型,使列位于不同的行中——允许使用索引。
一个选项使用 not exists
和 values()
:
select t.*
from mytable t
where not exists (
select 1
from (values(n1), (n2), (n3), (n4), (n5), (n6)) x(n)
where n in (3, 19)
)
当列表中的列数 and/or 值增加时,这比您的原始查询更好地缩放 - 尽管这不一定更有效。
Id | n1 | n2 | n3 | n4 | n5 | n6 --: | -: | -: | -: | -: | -: | -: 103 | 6 | 12 | 25 | 27 | 28 | 33
将一组不需要的值放在 CTE 中并使用 Except 运算符
正如其他人所指出的,数据模型并不理想。
要解决 NOT IN
过滤器的低效问题,您可以像这样使用 EXCEPT 运算符:
--sample data
WITH smple ( id, n1, n2, n3, n4, n5, n6) AS
( SELECT 100, 3, 10, 26, 31, 35, 39
union all
select 101,1,3,11,22,36,40
union all
select
102,10,19,20,30,39,40
union all
select
103,6,12,25,27,28,33
),
--end sample data
not_vals (n) as (select 3 union all select 19 )
SELECT
s.*
FROM
smple s
EXCEPT
SELECT
s.*
FROM
smple s join not_vals nv on
nv.n IN ( s.n1, s.n2, s.n3, s.n4, s.n5, s.n6)
;
从性能的角度看一下可以使用的各种方法的效率会很有趣。
最终解决方案应该具有良好的性能,因此相关子查询可能无法提供。
这是一个相关子查询:
--sample data
with smple ( id, n1, n2, n3, n4, n5, n6) AS
( SELECT 100, 3, 10, 26, 31, 35, 39
union all
select 101,1,3,11,22,36,40
union all
select
102,10,19,20,30,39,40
union all
select
103,6,12,25,27,28,33
),
--end sample data
not_vals (n) as (select 3 union all select 19 )
SELECT
s.*
FROM
smple s
WHERE
NOT EXISTS (
SELECT 1 FROM not_vals nv
WHERE
nv.n IN ( s.n1, s.n2, s.n3, s.n4, s.n5, s.n6)
)
;