计算列中不同值的最快方法,包括NULL值

Yaa*_*lis 10 sql t-sql database sql-server asp.net

Transact-Sql Count Distinct操作计算列中的所有非空值.我需要计算一组表中每列的不同值的数量,包括空值(所以如果列中有空值,结果应该是(Select Count(Distinct COLNAME) From TABLE) + 1.

这将在DB中每个表的每一列上重复.包括数百个表,其中一些表有超过1M行.因为这需要在每一列上完成,所以为每列添加索引不是一个好选择.

这将作为ASP.net站点的一部分完成,因此与代码逻辑的集成也可以(即:这不必作为一个查询的一部分完成,但如果可以以良好的性能完成,那么甚至更好).

最有效的方法是什么?


测试后更新

我从一个很好的代表性表格中给出的答案中测试了不同的方法.该表有320万条记录,数十列(少数有索引,大多数没有).一列有320万个唯一值.其他列的范围从所有Null(一个值)到最多40K唯一值.对于每种方法,我进行了四次测试(每次尝试多次,平均结果):一次20列,一次5列,1列有很多值(3.2M),1列有少量值( 167).以下是结果,按最快到最慢的顺序排列

  1. Count/GroupBy(Cheran)
  2. CountDistinct + SubQuery(Ellis)
  3. dense_rank(埃里克森)
  4. 伯爵+马克斯(Andriy)

测试结果(以秒为单位):

   Method          20_Columns   5_Columns   1_Column (Large)   1_Column (Small)
1) Count/GroupBy      10.8          4.8            2.8               0.14       
2) CountDistinct      12.4          4.8            3                 0.7         
3) dense_rank        226           30              6                 4.33 
4) Count+Max          98.5         44             16                12.5        
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 有趣的是,两个最快的方法(到目前为止,之间只有很小的差异)都是为每个列提交单独查询的方法(在结果#2的情况下,查询包含一个子查询,所以那里真的是每列提交两个查询).也许是因为通过限制表扫描数量所获得的收益与内存需求方面的性能损失相比较小(只是猜测).
  • 虽然dense_rank方法绝对是最优雅的,但似乎它不能很好地扩展(看到20列的结果,这是迄今为止四种方法中最差的),即使是小规模也无法与表现Count.

感谢您的帮助和建议!

Che*_*vel 9

SELECT COUNT(*)
FROM (SELECT ColumnName
      FROM TableName
      GROUP BY ColumnName) AS s;
Run Code Online (Sandbox Code Playgroud)

GROUP BY选择包括NULL的不同值. COUNT(*)将包括NULL,而不是COUNT(ColumnName)忽略NULL.


Mik*_*son 7

我认为您应该尝试保持表扫描的数量,并一次计算一个表中的所有列.这样的事情值得尝试.

;with C as
(
  select dense_rank() over(order by Col1) as dnCol1,
         dense_rank() over(order by Col2) as dnCol2
  from YourTable
)
select max(dnCol1) as CountCol1,
       max(dnCol2) as CountCol2
from C       
Run Code Online (Sandbox Code Playgroud)

SE-Data上测试查询

  • @Yaakov - `1,2,3`具有不同的值,因此排名不同. (3认同)