2011-02-10 245 views
2

如果您想知道COUNT(*)> 0,那么您可以使用EXISTS使查询更有效。如果我想知道COUNT(*)> 1,有没有办法让查询更高效?SQL:使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) 

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

+0

我不知道这是否仅是一个MySQL特定优化,而是有你试过`COUNT(primaryKeyField)> 1`或`COUNT(1)> 1`看看是否更好地使用索引? – PatrikAkerstrand 2011-02-10 14:48:16

+2

@Ardman - 我想这个问题是关于某些基数的,如果你说每个组有1,000行,并且在前两次匹配之后可以停止扫描,类似于'EXISTS'不需要'计算'所有匹配的行。 – 2011-02-10 14:51:01

+0

我能想到SQL Server使用`TOP`和`CROSS APPLY`的具体方式。 – 2011-02-10 14:59:06

回答

1

像这样的东西可以工作:

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

虽然如果我有你准确的查询,或合理的facsimilie,我可以帮你的更多信息。

据我所知,就实际的关键字而言,效率更高,作为SQL编程人员可以做的事情并不多。这将成为你的RDBMS如何处理实际计数的函数。如果它发现如果有2个事件会返回该行并停止计数为2,那么很好。如果它不够聪明并且追踪另外1,000次事件,那就不是那么好。

如果您在联接或子查询中使用此选项,则可以控制查询或存储过程中各个点返回的行数。您可以越早筛选出注定不会返回的行,效果会更好。

-1

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

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

select id 
from mytable 
where ... 
limit 2 

这应该是非常快的。比呼叫countRows哪些是给你给你需要的答案。

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 
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. 
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

0

我发现下面的行显著提高SQL Server的性能,在我的测试中,从40ms左右至约5毫秒去。

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