从表中选择count(distinct userID)的另一种方法是什么?

时间:2009-07-20 17:43:00

标签: sql sql-server optimization

是否有更快的方法从表中选择不同的用户数?也许使用row_number,分区或交叉应用?

我现在想不起来。

示例:

Table UsageLog

UserId     Date     StoreNumber
Alice      200901   342
Alice      200902   333
Alice      200902   112
Bob        200901   112
Bob        200902   345
Charlie    200903   322

这是我当前的查询:

select count(distinct userID), date
from
   UsageLog
where
   date between 200901 and 200902
group by date

我的实际表有数百万行,所有列实际上都是整数。

有更快的方法来获取用户列表吗?

修改

我已经在所有单独的列上都有非聚簇索引。出于某种原因,执行计划显示我仍在进行表扫描。我想我应该在Date上创建一个聚簇索引。我会看看它是如何运作的......

6 个答案:

答案 0 :(得分:3)

总的来说,我没有找到比你那里更快的方法,COUNT(DISTINCT UserId)是一个非常基本的查询。

这里最重要的是确保您在表上有一个索引,该索引适用于“日期”列和UserId列

答案 1 :(得分:2)

Date和UserId上的复合索引应该有很多帮助

答案 2 :(得分:2)

SELECT DISTINCT()是要走的路。问题是您正在点击date index tipping point,因此您的计划将用于聚集索引扫描。请参阅Kimberley L. Tripp文章的链接,了解“引爆点”是什么。

您需要覆盖索引:

CREATE INDEX idx_UsageLog_date_user_id ON UsageLog(date) INCLUDE (userID);

聚集索引也可以使用,但也有其他副作用。如果date上的聚簇索引与其他数据访问模式一致,则优于我建议的覆盖索引。

<强>更新

您在(userID, date)上尝试的逆序索引也有效,将搜索每个用户ID。实际上比(date, userID)(date) INCLUDE (userID)更好,因为它返回预先排序的userID,因此DISTINCT不会引入额外的排序。

我仍然建议查看我发布的链接,了解为什么'每个列的索引'没有帮助。

答案 3 :(得分:1)

使用GROUP BY并确保您在UserId

上有索引

答案 4 :(得分:1)

我跑了几个快速测试。

日期和用户ID上的一个索引:执行计划显示索引搜索,但随后执行排序以执行非常慢的。

UserID和Date上的一个索引:执行计划显示索引扫描和两个计算,这导致我运行的所有方案的成本更低。

仅使用Date或仅带有索引的UserID的其他方案比前一个更昂贵。

答案 5 :(得分:0)

你试过分组吗?

例如:

select count(userID), userID
  from UsageLog
 where date between 200901 and 200902
Group by userID

然后对两者做一个解释计划来比较性能。