有没有更好的方法来执行这样的查询:
SELECT COUNT(*)
FROM (SELECT DISTINCT DocumentId, DocumentSessionId
FROM DocumentOutputItems) AS internalQuery
我需要计算这个表中两列之间不同项的数量,我的查询已经正常工作但是我想知道是否可以只使用一个查询语句得到最终结果(不使用子查询)。
有没有更好的方法来执行这样的查询:
SELECT COUNT(*)
FROM (SELECT DISTINCT DocumentId, DocumentSessionId
FROM DocumentOutputItems) AS internalQuery
我需要计算这个表中两列之间不同项的数量,我的查询已经正常工作但是我想知道是否可以只使用一个查询语句得到最终结果(不使用子查询)。
如果您想提高性能,可以尝试在两个列的哈希值或连接值上创建一个持久化计算列。
一旦它被持久化,只要该列是确定性的且您正在使用“合理”的数据库设置,就可以在其上创建索引和/或统计信息。
我相信计算列的不同计数将等同于您的查询。
编辑:从不太可靠的仅校验和查询中进行修改
我发现了一种方法(在SQL Server 2005中),可以很好地运作,并且我可以使用尽可能多的列(通过将它们添加到CHECKSUM()函数中)。REVERSE()函数将int类型转换成varchar类型,以使得去重更加可靠。
SELECT COUNT(DISTINCT (CHECKSUM(DocumentId,DocumentSessionId)) + CHECKSUM(REVERSE(DocumentId),REVERSE(DocumentSessionId)) )
FROM DocumentOutPutItems
要作为单个查询运行,请连接列,然后获取连接字符串实例的不同计数。
SELECT count(DISTINCT concat(DocumentId, DocumentSessionId)) FROM DocumentOutputItems;
在MySQL中,您可以不需要连接步骤直接执行以下操作:
SELECT count(DISTINCT DocumentId, DocumentSessionId) FROM DocumentOutputItems;
这个功能在MySQL文档中有提到:
http://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_count-distinct
SELECT COUNT(DISTINCT (DocumentId, DocumentSessionId)) FROM DocumentOutputItems;
我会尽力使翻译通俗易懂,但不会对原文进行解释或添加额外的内容。 - ijosephDocumentID | DocumentSessionID
"A" | "AB"
"AA" | "B"
- Bort你现有的查询有什么不满意的地方吗?如果你担心在两个列上使用DISTINCT不能返回唯一的排列,为什么不试一下呢?在Oracle中,它确实像你期望的那样工作。
SQL> select distinct deptno, job from emp
2 order by deptno, job
3 /
DEPTNO JOB
---------- ---------
10 CLERK
10 MANAGER
10 PRESIDENT
20 ANALYST
20 CLERK
20 MANAGER
30 CLERK
30 MANAGER
30 SALESMAN
9 rows selected.
SQL> select count(*) from (
2 select distinct deptno, job from emp
3 )
4 /
COUNT(*)
----------
9
SQL>
编辑
我在分析数据时走了一条死胡同,但答案却令人沮丧地显而易见...
SQL> select count(distinct concat(deptno,job)) from emp
2 /
COUNT(DISTINCTCONCAT(DEPTNO,JOB))
---------------------------------
9
SQL>
编辑2
给定以下数据,上面提供的连接解决方案将会计算错误:
col1 col2
---- ----
A AA
AA A
所以我们需要添加一个分隔符...
select col1 + '*' + col2 from t23
/
显然,所选的分隔符必须是一个字符或一组字符,它们在任一列中都永远不会出现。
一些SQL数据库可以使用元组表达式,因此您可以这样做:
SELECT COUNT(DISTINCT (DocumentId, DocumentSessionId))
FROM DocumentOutputItems;
如果您的数据库不支持此功能,可以按照 @oncel-umut-turer 的建议使用 CHECKSUM 或其他标量函数来模拟实现良好唯一性,例如 COUNT(DISTINCT CONCAT(DocumentId, ':', DocumentSessionId))
。
MySQL 特别支持非 SQL 标准语法的 COUNT(DISTINCT expr, expr, ...)
。它还指出,在标准 SQL 中,您必须对 COUNT(DISTINCT ...) 中的所有表达式进行连接。
元组的一个相关用途是执行诸如 IN
查询之类的操作:SELECT * FROM DocumentOutputItems
WHERE (DocumentId, DocumentSessionId) in (('a', '1'), ('b', '2'));
可以尝试使用以下语句:
select count(*) from (select count(*) cnt from DocumentOutputItems group by DocumentId, DocumentSessionId) t1
这个语句与您已经使用的语句可能是一样的,但它避免了使用 DISTINCT 关键字。
下面是不带子查询的简短版本:
SELECT COUNT(DISTINCT DocumentId, DocumentSessionId) FROM DocumentOutputItems
在MySQL中它能够很好地工作,我认为优化器更容易理解这个。
编辑:显然,我误读了MSSQL和MySQL - 对此感到抱歉,但也许这有所帮助。
COUNT(DISTINCT CHECKSUM([Field1], [Field2])
- Custodio我已经使用过这种方法,并且它对我有效。
SELECT COUNT(DISTINCT DocumentID || DocumentSessionId)
FROM DocumentOutputItems
对于我的情况,它提供了正确的结果。
如果你正在使用固定长度的数据类型,你可以将其转换为二进制
,这样就可以非常简单和快速地完成此操作。假设DocumentId
和DocumentSessionId
都是int
,因此长度为4个字节...
SELECT COUNT(DISTINCT CAST(DocumentId as binary(4)) + CAST(DocumentSessionId as binary(4)))
FROM DocumentOutputItems
SUM
除以各种外键和日期字段的不同组合的COUNT
,同时按照另一个外键进行分组并偶尔通过一些值或键进行过滤。该表非常大,在使用子查询时,查询时间急剧增加。由于复杂性,统计数据根本不是可行的选择。使用CHECKSUM
方案在转换速度上也太慢了,特别是由于各种数据类型,我不能冒险使用其不可靠性。SUM
相比),且应该是完全可靠的!它应该能够帮助其他遇到类似情况的人,所以我在此发布。Select DocumentId, DocumentSessionId, count(*) as c
from DocumentOutputItems
group by DocumentId, DocumentSessionId;