“选择前10名,然后选择加入表”,而不是“从连接表中选择前10名”

时间:2011-12-07 16:50:29

标签: sql sql-server stored-procedures

我继承了一个存储过程,该存储过程在八个表中执行连接,其中一些表包含数十万行,然后从该连接的结果中选择前十个条目。

我在过程开始时有足够的信息从一个表中选择那十行,然后在这十行上执行这些连接,而不是在数十万个中间行上执行。

如何选择那些前十行,然后只对这十行进行连接,而不是在表中的所有数千行中执行连接?

3 个答案:

答案 0 :(得分:9)

我应该尝试:

SELECT * FROM
    (SELECT TOP 10 * FROM your_table
     ORDER BY your_condition) p
INNER JOIN second_table t
    ON p.field = t.field

答案 1 :(得分:1)

  1. 如果您有内部联接,优化程序可能无法首先执行前10个,因为它无法确定内部联接在以后不会排除行。如果它从主表中选择了10行,那么这将是一个错误,然后由于连接而在末尾仅返回7行。使用Marco的重写可能会因此而获得性能,因为您明确声明在连接之前限制行是安全的。
  2. 如果您的查询过于复杂,查询计划优化程序可能会在时间上找不到合适的计划。它只给出了几百毫秒,即使只有几个连接,也可能有数千种不同的方式来执行查询(不同的连接顺序等)。如果是这种情况,您将首先将前10行存储在临时表中,然后再使用它,如下所示:

    select top 10 *
    into #MainResults
    from MyTable
    order by your_condition;
    
    
    select *
    from #MainResults r
    join othertable t
      on t.whatever = r.whatever;
    

    我已经看到第二种方法产生了巨大差异的情况。

答案 2 :(得分:0)

您还可以使用CTE定义顶部X,然后使用它

例如,此data.se query仅限于前40个代码

with top40 as (
  select top 40 t.id, t.tagname
  from tags t, posttags pt
  where pt.tagid = t.id
  group by t.tagname, t.id
  order by count(pt.postid) desc
),

myanswers as(
  select p.parentid, p.score
  from posts p
  where
    p.owneruserid = ##UserID## and
    p.communityowneddate is null
)

select t40.tagname as 'Tag', sum(p1.score) as 'Score',
case when sum(p1.score) >= 15 then ':-)' else ':-(' end as 'Status'
from top40 t40, myanswers p1, posttags pt1
where
  pt1.postid = p1.parentid and
  pt1.tagid = t40.id
group by t40.tagname
order by sum(p1.score) desc