【问题标题】:can I get count() and rows from one sql query in sql server?我可以从 sql server 中的一个 sql 查询中获取 count() 和行吗?
【发布时间】:2012-08-03 01:03:54
【问题描述】:

我想获得一些查询的结果总数和前 n 行 - 有可能吗 在一份声明中?

我希望结果如下:

count(..) column1        column2
125         some_value   some_value
125         some_value   some_value

提前谢谢你!

【问题讨论】:

标签: sql sql-server tsql aggregate


【解决方案1】:

像这样:

SELECT TOP 100 --optional
    MC.Cnt, M.Column1, M.Column2
FROM
    myTable M
    CROSS JOIN
    (SELECT COUNT(*) AS Cnt FROM myTable) MC

编辑:在投票和 COUNT/OVER 回答之后。我的两张表的比较

您可以看到我的 CROSS JOIN/简单聚合和 COUNT/空 ORDER BY 子句之间的巨大差异

SELECT COUNT(*) OVER() AS C, key1col, key2col
FROM myTable

(24717 row(s) affected)

Table 'Worktable'. Scan count 3, logical reads 49865, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'myTable'. Scan count 1, logical reads 77, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

StmtText
  |--Nested Loops(Inner Join)
       |--Table Spool
       |    |--Segment
       |         |--Index Scan(OBJECT:([MyDB].[dbo].[myTable].[IX_useful]))
       |--Nested Loops(Inner Join, WHERE:((1)))
            |--Compute Scalar(DEFINE:([Expr1003]=CONVERT_IMPLICIT(int,[Expr1005],0)))
            |    |--Stream Aggregate(DEFINE:([Expr1005]=Count(*)))
            |         |--Table Spool
            |--Table Spool

SELECT
    MC.Cnt, M.key1col, M.key2col
FROM
    myTable M
    CROSS JOIN
    (SELECT COUNT(*) AS Cnt FROM myTable) MC

(24717 row(s) affected)

Table 'myTable'. Scan count 2, logical reads 154, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.


StmtText
  |--Nested Loops(Inner Join)
       |--Compute Scalar(DEFINE:([Expr1005]=CONVERT_IMPLICIT(int,[Expr1009],0)))
       |    |--Stream Aggregate(DEFINE:([Expr1009]=Count(*)))
       |         |--Index Scan(OBJECT:([MyDB].[dbo].[myTable].[IX_useful]))
       |--Index Scan(OBJECT:([MyDB].[dbo].[myTable].[IX_useful] AS [M]))

我在一个有 570k 行的表上重复了这个,这里是 IO

Table 'Worktable'. Scan count 3, logical reads 1535456, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'myTable'. Scan count 1, logical reads 2929, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.


Table 'myTable'. Scan count 34, logical reads 6438, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

【讨论】:

  • +1 用于拔出所有枪支。我得看看我的执行计划。
  • @Chris Bednarski:我以前被咬过! SET STATISTICS TIME ON 也很有用:CPU 是 x5 到 x10,持续时间 x2 用于我的 OVER 解决方案
  • @gbn:我现在有兴趣看看 2005 年和 2008 年之间的性能是否有很大差异。它在 2005 年像狗一样奔跑。
  • @Chris Bednarski:请让我们知道:之前和我的同事讨论过这个
  • 顺便说一下,在逻辑读取前面,这两个数字不能直接比较。 See this answer for details.
【解决方案2】:

怎么样

SELECT COUNT(*) OVER() AS C, COLUMN1, COLUMN2
FROM TABLE  

关于CROSS JOIN查询
在繁重的INSERT/DELETE 环境中,交叉连接将返回错误的行数。

从多个连接中尝试此操作
连接 1

set nocount on;
drop table dbo.test_table;
GO
create table dbo.test_table
(
    id_field uniqueidentifier not null default(newid()),
    filler char(2000) not null default('a')
);
GO
create unique clustered index idx_id_fld on dbo.test_table(id_field);
GO
while 1 = 1
insert into dbo.test_table default values;

连接 2

select T2.cnt, T1.id_field, T1.filler
from dbo.test_table T1
cross join (select COUNT(*) as cnt from dbo.test_table) T2

select T2.cnt, T1.id_field, T1.filler
from dbo.test_table T1
cross join (select COUNT(*) as cnt from dbo.test_table) T2

select T2.cnt, T1.id_field, T1.filler
from dbo.test_table T1
cross join (select COUNT(*) as cnt from dbo.test_table) T2

每次,记录数 (@@ROWCOUNT) 与 T2.cnt 不同

对于COUNT(*) OVER(),只有一次表扫描,@@ROWCOUNT 始终与T2.cnt 相同

关于查询计划 - SQL 2005 SP3 在执行COUNT(*) OVER() 方面似乎比 SQL 2008 R2 弱得多。最重要的是,它错误地报告了查询成本(我从没想过子查询的成本可能超过整个查询的 100%)。

在很多场景下,COUNT(*) OVER()的成本在CROSS JOIN的50-75%之间

交叉连接的最佳情况是,如果有一个非常窄的索引可以进行计数。这样,将对数据进行聚集索引扫描+对计数进行索引扫描。

与往常一样,最好是衡量、衡量、衡量,然后按照您乐于接受的折衷方案进行。

【讨论】:

  • 我打算提出同样的建议
  • 比连接好得多,仅使用单次扫描
  • 这是首选方法。
  • 您是否将性能与我的进行了比较?像狗一样奔跑。它必须在 WorkTable 中处理 COUNT
【解决方案3】:

可以使用CROSS JOIN 和 CTE 执行此操作,但效率不高:

WITH Rows_CTE AS
(
    SELECT Column1, Column2
    FROM Table
    WHERE (...)
)
SELECT c.Cnt, r.Column1, r.Column2
FROM Rows_CTE r
CROSS JOIN (SELECT COUNT(*) AS Cnt FROM Rows_CTE) c

我认为获得所需内容的更好方法是使用单个查询但多个结果集,您可以使用COMPUTE

SELECT Column1, Column2
FROM Table
WHERE (...)
COMPUTE COUNT([Column1])

【讨论】:

  • 为什么要使用 CTE?一个简单的交叉连接到派生表就可以了。并且 COMPUTE 也被弃用了。
  • @gbn:我确实使用了CROSS JOIN。 CTE 使得谓词可以被重用(注意包含WHERE (...),它在问题中没有出现,但可能包含在生产环境中)。而且我知道COMPUTE 在技术上已被弃用,但ROLLUP 不能在这里替换它,使用COMPUTE 可以消除计划中的整个表/索引扫描。
  • 坦率地说,他们弃用 COMPUTE 总是让我很恼火,因为它仍然是在没有 GROUP BY 子句的情况下计算聚合的唯一方法。但这是另一天的咆哮。
  • 我也喜欢 COMPUTE。该死的有用。
【解决方案4】:

试试这个查询:

select ColumnId,Descr,(select COUNT(*) from ColumnSetUp)as c
from ColumnSetUp
group by ColumnId,Descr

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-27
    • 2010-10-06
    • 2018-10-20
    • 2020-10-07
    • 2011-09-10
    • 1970-01-01
    相关资源
    最近更新 更多