查询此数据的更有效方法是什么?

时间:2010-08-23 09:57:51

标签: sql sql-server performance tuples

我有一张包含一些数据的表格:

 ColA | ColB | ColC
------+------+------
  1   |  A   |  X
  2   |  A   |  Y
  3   |  B   |  Y
  4   |  C   |  Y
  5   |  C   |  Z
  6   |  D   |  Y
  7   |  D   |  Z

我想查询以获取ColBColC 作为一对匹配条件的所有行:

SELECT * FROM [Table] 
WHERE (ColB = A AND ColC = Y)
OR (ColB = B AND ColC = Y)
OR (ColB = C AND ColC = Y)
OR (ColB = D AND ColC = Z)

这应该返回第2,3,4和7行。


(ColB,ColC)的值对可能很大(在~100的范围内)。除了具有大量OR条件的大型查询之外,是否有更有效的方法来查询此数据?

我希望有一种方法可以使用等效的元组,这意味着我可以做类似的事情:

SELECT * FROM [Table] 
WHERE (ColB, ColC) IN ({A, Y}, {B, Y}, {C, Y}, {D, Z})

有什么想法吗?


编辑:(回答评论中的一些问题)

ColBColC存储guid的字段,并声明为uniqueidentifier种类型。
这需要在SQL Server 2005上(所有版本)上工作 该表具有数百万行的顺序,我并不反对添加此工作所需的任何索引。

3 个答案:

答案 0 :(得分:4)

你可以这样做。 (如果您使用的是SQL Server 2008,则可以使用values行构造函数而不是union alls

您需要检查查询计划,看看它是否更有效。

SELECT * /*But don't use star*/
FROM [Table] 
JOIN 
(
SELECT 'A' AS BMatch, 'Y' AS CMatch UNION ALL
SELECT 'B' AS BMatch, 'Y' AS CMatch UNION ALL
SELECT 'C' AS BMatch, 'Y' AS CMatch UNION ALL
SELECT 'D' AS BMatch, 'Z' AS CMatch UNION ALL ...
) Matches
ON ColB = BMatch AND ColC = CMatch

您在评论中说ColBColC的组合是唯一的(假设您的表已经有聚集索引)我会想象您是否在任何一个上创建unique nonclustered index (colb, colc)(colc, colb)以上内容应该为您提供100个索引搜索计划,然后进行100次书签查找。如果不是,您可以尝试添加索引提示以使其使用新索引。您需要将其I / O与完整扫描的I / O进行比较,因为很多or s可能会给您。

通过在非聚集索引中包含其他必需列,可以避免书签查找的成本。你曾经使用*,所以我不知道这会有多可行。您需要平衡此查询的好处,以防止对数据修改操作造成不利影响。

答案 1 :(得分:3)

您是否考虑过添加calculated column作为两列的串联?

它将简化您的select语句,并允许添加索引。

CREATE TABLE [dbo].[Table] (
  ColA  INTEGER
  , ColB VARCHAR(1)
  , ColC VARCHAR(1)
  , ColBC AS ColB + ColC
)  

CREATE UNIQUE INDEX IX_TABLE_COLBC ON [dbo].[Table] (ColBC)

INSERT INTO [Table] VALUES(1, 'A', 'X')
INSERT INTO [Table] VALUES(2, 'A', 'Y')
INSERT INTO [Table] VALUES(3, 'B', 'Y')
INSERT INTO [Table] VALUES(4, 'C', 'Y')
INSERT INTO [Table] VALUES(5, 'C', 'Z')
INSERT INTO [Table] VALUES(6, 'D', 'Y')
INSERT INTO [Table] VALUES(7, 'D', 'Z')

不完全等同于元组,但它确实允许您将选择更改为

SELECT * FROM [Table] 
WHERE (ColBC) IN ('AY', 'BY', 'CY', 'DZ')

并使用索引。

答案 2 :(得分:1)

为什么不创建一个新表来过滤结果集?有大约100个要过滤的值,如果您的过滤条件将来发生变化,此解决方案将更灵活,即您只需更改过滤器表而不是更改将在您的select语句中嵌入的“where”子句: -

if exists(select * from sys.objects WHERE object_id = object_id(N'dbo.Filter')AND输入(N'U'))
    drop table dbo.Filter

创建表dbo.Filter(
    ColB char(1)not null,
    ColC char(1)not null,
    约束pkFilter主键聚簇(ColB,ColC),fillfactor = 100)

插入dbo.Filter(ColB,ColC)值('A','Y'),('B','Y'),('C','Y'),('D',' Z')

从[表]中选择*作为t
内部连接dbo.Filter as f on t.ColB = f.ColB and t.ColC = f.ColC