【问题标题】:Using LIKE in WHERE clause for GUIDs results in full table scan在 WHERE 子句中对 GUID 使用 LIKE 会导致全表扫描
【发布时间】:2019-07-03 19:58:03
【问题描述】:

我有一个看起来像这样的表:

CREATE TABLE Records 
(
    ID UNIQUEIDENTIFIER PRIMARY KEY NONCLUSTERED,
    owner UNIQUEIDENTIFIER,
    value FLOAT,
    timestamp DATETIME
)

与此问题无关的其他一些列上存在多列聚集索引。

该表目前大约有 500,000,000 行,我需要对表进行操作,但目前太大而无法处理(我受到慢硬件的阻碍)。所以我决定分块进行。

如果我说

SELECT ID 
FROM records
WHERE ID LIKE '0000%'

执行计划显示扫描了整个表。我认为使用索引,只有那些与原始条件匹配的行才会被扫描,直到 SQL 到达“0001”记录。有了前面的 %,我可以清楚地看到为什么它会扫描整个表。但是最后有 % ,它不应该扫描整个表。

我猜这与 GUID 而不是 CHARVARCHAR 列的工作方式不同。

所以我的问题是:如何在不必扫描整个表的情况下搜索 GUID 的一个小节?

【问题讨论】:

  • 如果可能的话,您可以通过添加一个将 id 转换为 char 的 char 列并为此列创建和索引来进行测试,然后检查查询
  • GUID 不是字符串,而是 GUID are not stored as they are printed 的字节。此查询需要转换所有单独的行,这当然效率不高。 应该可以通过构建适当的表单并使用>=< 进行比较(我认为LIKE 模式不起作用)来分块GUID 处理,但这并不完全是微不足道的。你可以试试ROW_NUMBER() 上的分块是否足够快;它肯定会简单得多。
  • @jeroen Mostert。这很有趣。因为我如何分块并不重要,我就是这么做的。如果 从左到右影响第 5 组,我可以轻松地动态构建边界。我会测试一下。
  • 对于任何订单(和UNIQUEIDENTIFIER)的东西肯定会起作用的一件事就是要求TOP(x) ORDER BY ...,跟踪最后一行你看到了,然后用WHERE ... > lastvalue发出下一个。这样一来,SQL Server 如何对 GUID 进行排序并不重要,只要您跟踪您离开的位置即可。
  • 话虽如此,除非您的列由NEWSEQUENTIALID() 填充(即使那样,因为它不是完全单调递增)添加新行将导致您的枚举中断并跳过行,这与@ 不同987654334@,这只是在正常情况下增加,即使它跳过值也是如此。所以请注意任何插入!

标签: sql-server sql-server-2012


【解决方案1】:

从您的 cmets 中,我看到实际需要是根据范围将随机 GUID 值的行分成块(有序)。在这种情况下,您可以指定一个范围而不是 LIKE 以及最后一组中所需的开始/结束值的过滤器:

SELECT ID
FROM dbo.records
WHERE
    ID BETWEEN '00000000-0000-0000-0000-000000000000'
    AND '00000000-0000-0000-0000-000FFFFFFFFF';

This article 解释了如何在 SQL Server 中存储和排序唯一标识符 (GUID),首先比较和排序最后一组,而不是您可能期望的从左到右的排序。通过对最后一组进行过滤,您将获得一个 sargable 表达式并仅触及指定范围内的那些行(假设使用了 ID 上的索引)。

【讨论】:

  • 可行,但要考虑字节顺序。我可以将表分成 4096 个大致相等的块,如下所示: SELECT ID FROM Records WHERE ID BETWEEN '00000000-000000000000' AND '00000000-0000-0000-0000-000FFFFFFFFF' 然后更改 000 的值在第 5 个字节组的开头。如果您想稍微编辑您的答案,我会将其标记为已关闭。谢谢。
  • 阅读这篇关于 GUID 如何在不同上下文中以不同方式排序的文章可能值得您阅读:devblogs.microsoft.com/oldnewthing/20190426-00/?p=102450
  • @RobertSievers,我参考该链接和您的特定用例改进了我的答案。这是another article 详细说明 SQL Server 排序的字节交换,以便为 SQL Server 生成顺序 GUID。
猜你喜欢
  • 1970-01-01
  • 2021-06-14
  • 2013-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-26
  • 2013-10-09
  • 1970-01-01
相关资源
最近更新 更多