【问题标题】:Query equivalence with DISTINCT使用 DISTINCT 查询等价
【发布时间】:2018-01-12 13:48:38
【问题描述】:

让我们使用以下脚本创建一个简单的表order(id: int, category: int, order_date: int)

IF OBJECT_ID('dbo.orders', 'U') IS NOT NULL  DROP TABLE dbo.orders

SELECT TOP 1000000
      NEWID() id, 
      ABS(CHECKSUM(NEWID())) % 100 category, 
      ABS(CHECKSUM(NEWID())) % 10000 order_date
INTO orders
FROM    sys.sysobjects
CROSS JOIN sys.all_columns

现在,我有两个等价的查询(至少我相信它们是等价的):

-- Q1
select distinct o1.category,
       (select count(*) from orders o2 where order_date = 1 and o1.category = o2.category) 
from orders o1

-- Q2
select o1.category,
       (select count(*) from orders o2 where order_date = 1 and o1.category = o2.category) 
from (select distinct category from orders) o1

但是,当我运行这些查询时,它们具有明显不同的特征。 Q2 对我的数据来说快了两倍,这显然是由于查询计划在加入之前首先找到唯一类别(以下查询计划中的哈希匹配)。

如果添加请求的索引,差异仍然存在

CREATE NONCLUSTERED INDEX ix_order_date ON orders(order_date)
INCLUDE (category)

此外,Q2 还可以有效地使用以下索引,而 Q1 保持不变:

CREATE NONCLUSTERED INDEX ix_orders_kat ON orders(category, order_date)

我的问题是:

  1. 这些查询是否等效?
  2. 如果是,SQL Server 2016 查询优化器在 Q1 的情况下找到第二个查询计划的障碍是什么(我相信这种情况下搜索空间一定很小)?
  3. 如果没有,您能否发布一个反例?

编辑

我提出这个问题的动机是,我想了解为什么查询优化器在重写简单查询方面如此糟糕,而且它们如此严重地依赖 SQL 语法。 SQL 语言是一种声明性语言,因此,为什么 SQL 查询处理器经常由语法驱动,即使对于这样的简单查询也是如此?

【问题讨论】:

  • 为什么不只是SELECT category, COUNT(*) FROM dbo.orders WHERE order_date = 1 GROUP BY category;?您是否简化了一个更复杂的问题?
  • 您可以使用@AaronBertrand 的查询发布查询计划吗?这将是您想要的结果的最典型示例。
  • @justiceorjustus 实际上,它不是前两个的等效查询。当没有order_date = 1 时,它会忽略类别
  • @RadimBača 也许然后去SELECT category, COUNT(CASE WHEN order_date = 1 THEN 1 END) FROM dbo.orders GROUP BY category;
  • @justiceorjustus 谢谢,条件聚合这会导致一次顺序扫描,这可能是好是坏取决于选择性,如下所示:stackoverflow.com/questions/45795898/… 也许我应该在我的问题中更清楚,我会想了解为什么查询优化器在重写简单查询方面如此糟糕,而且它们如此严重地依赖 SQL 语法。

标签: sql performance query-optimization sql-server-2016


【解决方案1】:

查询在功能上是等效的,这意味着它们应该返回相同的数据。

但是,SQL 引擎对它们的解释不同。第一个 (SELECT DISTINCT) 生成所有结果然后删除重复项。

第二个首先提取不同的值,因此子查询仅在适当的子集上调用。

索引可能会使任一查询更有效,但它不会从根本上影响distinct 处理是发生在子查询之前还是之后。

在这种情况下,结果是相同的。但是,根据子查询,这不一定是正确的。

【讨论】:

  • 我的意思是,SQL 是一种声明性语言。因此,我希望查询优化器在这种简单的情况下找到相同的查询计划。
  • @RadimBača。 . .我不知道有任何数据库会使用子查询进行这种优化。这取决于子查询的内容,这可能很难破译。
猜你喜欢
  • 2020-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多