【问题标题】:More efficient way of querying for this data?查询此数据的更有效方式?
【发布时间】:2010-08-23 09:57:51
【问题描述】:

我有一个表格,里面有一些数据:

科尔A |科尔B |科尔C ------+------+------ 1 |一个 | X 2 |一个 |是 3 |乙|是 4 | C |是 5 | C | Z 6 | D |是 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})

有什么想法吗?


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

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

【问题讨论】:

  • 您能否提供 ColB 和 ColC 的数据类型?如果它们是文本,也许使用正则表达式可以帮助你,但我对 sql-server 知之甚少,无法说出它们是否支持正则表达式、扩展程度或方式。
  • 什么版本的 SQL Server?你有什么索引?你想强制执行什么计划? 100 次索引查找或索引扫描?表中有多少条记录?
  • 还有几个问题。 ColBColC 是唯一的吗?如果不是,这对组合是唯一的吗?
  • @Martin: ColBColC 在表中不是唯一的,但它们两者的组合是。

标签: sql sql-server performance tuples


【解决方案1】:

你可以这样做。 (如果您使用的是 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

您在 cmets 中说 ColBColC 的组合是独一无二的,所以(假设您的表已经有一个聚集索引)我想如果您在 (colb, colc) 或 @987654329 上创建一个 unique nonclustered index @ 上面应该给你一个计划,其中包含 100 个索引查找,然后是 100 个书签查找。如果不是,您可以尝试添加索引提示以使其使用新索引。您需要将它的 I/O 与完整扫描的 I/O 进行比较,因为很多 ors 可能会给您。

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

【讨论】:

  • 这看起来最有希望,但与我最初问题中的OR 解决方案相比,在我拥有的数据的执行计划/时间方面表现不佳。我最终使用了OR 解决方案。
【解决方案2】:

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

这将简化您的选择语句并允许添加索引。

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')

它使用索引。

【讨论】:

    【解决方案3】:

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

    如果存在(从 sys.objects 中选择 * WHERE object_id = object_id(N'dbo.Filter') 并输入 (N'U'))
    删除表 dbo.Filter

    创建表 dbo.Filter (
    ColB char(1) 不为空,
    ColC char(1) 不为空,
    约束 pkFilter 主键聚集 (ColB,ColC) with fillfactor = 100)

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

    从 [Table] 中选择 * 作为 t
    在 t.ColB = f.ColB 和 t.ColC = f.ColC 上将 dbo.Filter 内连接为 f

    【讨论】:

      猜你喜欢
      • 2013-08-31
      • 1970-01-01
      • 1970-01-01
      • 2020-05-21
      • 2020-08-27
      • 1970-01-01
      • 2012-01-06
      • 2016-04-30
      • 2015-04-05
      相关资源
      最近更新 更多