我应该在SubQuery中使用Top(1)吗?

时间:2009-01-30 16:15:35

标签: sql subquery

示例查询:

select * 
from A join B on A.ID = B.SOMEVALUE
where A.VALUE="something" and
B.ID = 
       (select ID from B where SOMEVALUE = A.ID and 
              THISDATE = (select max(SOMEDATE) from B where ...))

所以,如果你能阅读SQL,你应该看到我正在做几个相关的子查询来缩小连接的结果。 (是的,这非常简化)。

在某些情况下子查询:

select ID from B where SOMEVALUE = A.ID and 
    THISDATE = (select max(SOMEDATE) from B where ...)

可以返回多于1个值,这会导致错误

  

“子查询返回的值超过1。   这是不允许的   子查询跟随=,!=,<,< =,>,> =   或者子查询用作   表述“。

我完全期待。这显然不是一件好事,我有代码(希望)防止这些副本首先进入数据库(即表B 应该只有1行匹配

SOMEVALUE = A.ID and max(SOMEDATE)

条件),但最终用户如果没有创造性,却找不到破解软件的方法。

现在问我的问题:

将第一个子查询更改为

会更好吗?
select top 1 * from B ...

防止用户在/ if(希望永远不会)出现这种情况或让错误发生时看到错误。我倾向于不添加top语句并让错误通过而不是让用户看到可能不正确的数据。我想知道在这样的情况下是否有人对最佳实践有任何想法......

6 个答案:

答案 0 :(得分:11)

通常TOP 1是个好主意。

考虑一个包含数百万行的大型表,而您所匹配的列上没有索引,但是您只需查找一行。

SELECT TOP 1表示只要找到一个项目,表扫描就会停止。

如果没有TOP 1,表格扫描将一直持续到最后。

与涉及扫描(或蛮力)进行搜索的任何事情一样。使用TOP 1,它应该比不使用TOP 1平均快50%。

但是,根据您需要返回的内容,通常可以通过使用EXISTS获得真正的性能提升。

而不是写

SELECT * FROM table t
WHERE t.id = (SELECT TOP 1 foreignid from table2)

您可以使用

SELECT * FROM table t
WHERE EXISTS (SELECT 1 from table2 WHERE foreignid = t.id)

答案 1 :(得分:4)

为什么要加入表A和B ...然后在子查询中从B中选择...并与A ???中的列进行比较

这不等同于:

select * 
from A join B on A.ID = B.SOMEVALUE
where A.VALUE="something" and
THISDATE = (select max(SOMEDATE) from B where ...))

此外,如果您希望从整个查询中获得一行总数......这不会起作用:

select top 1 * 
from A join B on A.ID = B.SOMEVALUE
where A.VALUE="something" 
Order by B.SOMEDATE DESC

答案 2 :(得分:4)

编码练习:将top1放在子查询中,该子查询需要返回单个值。

优点:

  • 允许继续执行。
  • 允许查询忽略无意义的额外值。
  • 在找到第一个值时停止查找新值(执行)。

缺点:

  • 防止查询抱怨重要的额外值。
  • 如果查询中未指定顺序,则无法控制top1将选择哪个元素。当第二次执行查询时,这会导致不同的结果。

答案 3 :(得分:1)

我推荐使用TOP 1方法。它可能有助于提高性能(不太可能伤害它)。

没有它你会发现错误的想法是光荣的,但有点错位。如果从现在起几个月内发生错误,那么它根本不会直观或者发生了什么。相反,我专注于在其他地方强制执行数据完整性。

答案 4 :(得分:0)

为什么不在子选择的末尾使用LIMIT 1

答案 5 :(得分:0)

如果您只想返回一行,则可以执行以下两项操作之一。第一种是改变你的平等检查,而不是像这样检查包含

select ID from B where SOMEVALUE = A.ID and 
THISDATE IN (select max(SOMEDATE) from B where ...)

(注意IN)

其次你可以做到

select TOP 1 ID from B where SOMEVALUE = A.ID and 
THISDATE IN (select max(SOMEDATE) from B where ...)

如果你只是只找一个值。

或者如您所说,您可以将子查询更改为SELECT TOP 1,在我看来,这是正常的,因为只要WHERE子句不依赖于外部查询,它就可能执行嵌套查询只有一次并依赖于那里的静态存储值,如此

select ID from B where SOMEVALUE = A.ID and 
THISDATE = (select TOP 1 * from B where ...)

所以有一些选择,但我不完全确定它们的效率。