4

示例查询:

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,您应该会看到我正在执行几个相关的子查询来缩小 join 的结果。(是的,这太简单了)。

在某些情况下,子查询:

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

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

4

6 回答 6

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)
于 2009-01-30T16:20:51.523 回答
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
于 2009-01-30T16:22:17.417 回答
4

编码实践:将 top1 放在需要返回单个值的子查询中。

优点:

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

缺点:

  • 防止查询抱怨重要的额外值。
  • 如果查询中未指定 order,则无法控制 top1 将选择哪个元素。当第二次执行查询时,这可能会导致不同的结果。
于 2009-01-30T16:24:05.073 回答
1

我会推荐 TOP 1 方法。它可能会帮助性能(不太可能伤害它)。

没有它你会发现错误的想法是光荣的,但有点错位。如果从现在开始几个月后这里发生错误,那么它发生的原因或正在发生的事情根本不直观。相反,我会专注于在其他地方强制执行数据完整性。

于 2009-01-30T16:23:08.990 回答
0

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

于 2009-01-30T16:20:45.127 回答
0

如果你只想返回一行,你可以做两件事之一。首先是改变你的平等检查,而不是像这样检查遏制

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

(注意输入)

其次你可以做

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

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

于 2009-01-30T16:21:52.253 回答