使用DISTINCT

时间:2018-01-12 13:48:38

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

让我们使用以下脚本创建一个简单的表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快两倍,这显然是由于查询计划在加入之前首先找到唯一类别(以下查询计划中的哈希匹配)这一事实。

enter image description here

如果添加请求索引

,差异仍然存在
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. 如果不是,你可以张贴一个反例吗?
  4. 修改

    我对这个问题的动机是,我想理解为什么查询优化器在重写甚至简单查询方面都很差,而且它们依赖于SQL语法。 SQL语言是一种声明性语言,因此,为什么SQL查询处理器经常被语法驱动,即使是像这样的简单查询呢?

1 个答案:

答案 0 :(得分:0)

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

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

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

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

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