SQL:制作COUNT(*)> 1高​​效

时间:2011-02-10 14:44:59

标签: sql performance count

如果你想知道COUNT(*)> 0然后您可以使用EXISTS来提高查询效率。当我想知道COUNT(*)>时,我是否有办法提高查询效率? 1?

(需要与SQL Server和Oracle兼容。)

谢谢,杰米

编辑:

我正在尝试提高某些代码的性能。有一些类似于:

if (SQL('SELECT COUNT(*) FROM table WHERE a = b') > 0) then...

if (SQL('SELECT COUNT(*) FROM table WHERE a = b') > 1) then...

第一行很容易切换到EXISTS语句,但是我可以使第二行更有效吗?从评论和我自己的想法,我有以下的想法,他们中的任何一个会更有效吗?

if (SQLRecordCount('SELECT TOP 2 1 FROM table WHERE a = b') > 1) then...

(我可以将ROWNUM用于Oracle。)

if (SQL('SELECT 1 FROM table WHERE a = b HAVING COUNT(*) > 1') = 1) then...

以下在SQL Server中不起作用:

SELECT COUNT(*) FROM (SELECT TOP 2 FROM table WHERE a = b)

但这与Oracle有关:

SELECT COUNT(*) FROM (SELECT 1 FROM table WHERE a = b AND ROWNUM < 3)

到目前为止,感谢您的帮助。

6 个答案:

答案 0 :(得分:1)

这样的事情可行:

select myDate
from myTable
where myColumn = myCondition
group by myDate
having count(*) > 1

虽然如果我有你的确切查询或合理的传真,我可以帮助你更多。

就实际的关键字效率而言,据我所知,关于它的SQL程序员并不多。这将是你的RDBMS如何处理实际计数的函数。如果它看到它将返回该行,如果有2次发生并且停止计数为2,那么很好。如果它不够智能并且跟踪另外1000次出现,那就不那么好了。

如果您在连接或子查询中使用它,则可以控制在查询或存储过程中的各个点返回的行数。您可以越早过滤掉永远不会返回的行,就越好。

答案 1 :(得分:1)

目前你的问题有点抽象。你能提供更多的背景吗?

我在想,如果你在foo, id上有一个综合索引,那么下面的索引可以通过两次索引搜索得到满足。

SELECT CASE WHEN MAX(id)= MIN(id) THEN 0 ELSE 1 END
FROM yourtable 
WHERE foo='bar'

或许可以更明确地强制计划

SELECT CASE WHEN COUNT(*) = 2 THEN 1 ELSE 0 END FROM 
(
    SELECT MAX(id)
    FROM yourtable 
    WHERE foo='bar'
    UNION
    SELECT MIN(id)
    FROM yourtable 
    WHERE foo='bar'
) AS T

答案 2 :(得分:1)

如果索引

,那应该没那么重要

示例:

200万行表,相当宽,900MB磁盘,虚拟SQL Server 2005。

这提供了17,876行

SELECT COUNT(*), ThingID FROM dbo.TwoMillion IT GROUP BY ThingID HAVING COUNT(*) > 1

  |--Filter(WHERE:([Expr1002]>(1)))
       |--Compute Scalar(DEFINE:([Expr1002]=CONVERT_IMPLICIT(int,[Expr1005],0)))
            |--Hash Match(Aggregate, HASH:([IT].[ThingID]) DEFINE:([Expr1005]=COUNT(*)))
                 |--Index Scan(OBJECT:([MyDB].[dbo].[TwoMillion].[IX_Thing] AS [IT]))

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0
Table 'TwoMillion'. Scan count 1, logical reads 8973, physical reads 3, read-ahead reads 8969... all zeroes

第二次运行

 Table 'Worktable'. = same
 Table 'TwoMillion'. Scan count 1, logical reads 8973, ... all zeroes

 CPU time = 453 ms,  elapsed time = 564 ms.

答案 3 :(得分:0)

完全忽略SQL Server中的交叉兼容性要求,您可以使用TOP显式限制扫描的行数。在某些情况下,这可能是有益的,如下面(有点人为的)例子。

USE tempdb

CREATE TABLE Orders
(
OrderId INT IDENTITY(1,1) PRIMARY KEY,
Blah VARCHAR(10)
)
INSERT INTO Orders 
SELECT TOP 10 LEFT(name,10)
FROM sys.objects

CREATE TABLE OrderItems
(
OrderItemId INT IDENTITY(1,1) PRIMARY KEY,
OrderId INT REFERENCES Orders(OrderId)
)
CREATE NONCLUSTERED INDEX ix ON OrderItems(OrderId)

INSERT INTO OrderItems (OrderId)
SELECT TOP 1000000 1+ ROW_NUMBER() OVER (ORDER BY (SELECT 0))% 10 
FROM sys.all_columns c1, sys.all_columns c2

SET STATISTICS IO ON
SET STATISTICS TIME ON

SELECT o.OrderId, o.Blah
FROM Orders o JOIN OrderItems oi ON o.OrderId = oi.OrderId
GROUP BY o.OrderId, o.Blah
HAVING COUNT(*) > 1

/*
Table 'Orders'. Scan count 0, logical reads 20
Table 'OrderItems'. Scan count 1, logical reads 1742
*/


SELECT o.OrderId, o.Blah
FROM Orders o 
CROSS APPLY 
(SELECT TOP 2 OrderItemId FROM 
OrderItems oi WHERE o.OrderId = oi.OrderId) CA
GROUP BY o.OrderId, o.Blah
HAVING COUNT(*) > 1

/*
Table 'OrderItems'. Scan count 10, logical reads 30
Table 'Orders'. Scan count 1, logical reads 2
*/

DROP TABLE OrderItems
DROP TABLE Orders

Execution Plan

答案 4 :(得分:0)

我发现以下行显着改善了SQL Server的性能,在我的测试中从大约40ms到大约5ms。

SELECT COUNT(*) FROM (SELECT TOP 2 1 AS x FROM table Where a = b) AS y

注意别名,它们是使查询起作用所必需的。

不幸的是,以下查询似乎没有提高Oracle的性能:

SELECT COUNT(*) FROM table WHERE a = b AND ROWNUM < 3

答案 5 :(得分:-1)

首先,如果要优化查询,则不应使用星号。

也许最好创建一个带限制的查询?你对伯爵或类似的东西不感兴趣。您只想知道是否有多个条目:

select id
from mytable
where ...
limit 2

这应该非常快。比调用countRows给你,以获得你需要的答案。