有没有更好的方法来排序此查询?

时间:2009-12-16 16:47:21

标签: sql sql-server orm

我们在程序上生成了很多SQL,SQL Server正在杀死我们。由于记录了elsewhere的一些问题,我们基本上做了SELECT TOP 2 ** 32而不是TOP 100 PERCENT。

注意:我们必须使用子查询。

这是我们的查询:

SELECT * FROM ( 
    SELECT [me].*, ROW_NUMBER() OVER( ORDER BY (SELECT(1)) ) 
    AS rno__row__index FROM (
       SELECT [me].[id], [me].[status] FROM (
          SELECT TOP 4294967296 [me].[id], [me].[status] FROM 
          [PurchaseOrders] [me] 
          LEFT JOIN [POLineItems] [line_items] 
          ON [line_items].[id] = [me].[id] 
          WHERE ( [line_items].[part_id] = ? ) 
          ORDER BY [me].[id] ASC
       ) [me]
   ) [me] 
) rno_subq 
WHERE rno__row__index BETWEEN 1 AND 25 

有没有更好的方法可以让任何人看到这个?

更新:以下是对整个子查询问题的一些澄清:

我的问题的关键词是“程序性的”。我需要能够可靠地封装结果集,以便它们可以像构建块一样堆叠在一起。例如,我想得到按照制作它们的艺术家的名字排序的前10个CD,并且还获得每个CD的相关艺术家。我所做的是组装一个单片子选择,表示由连接的艺术家名称排序的cds,然后对其应用限制,然后将嵌套的子选择连接到艺术家表,然后执行生成的查询。隔离是必要的,因为请求有序cds的代码是无关的,并且无视选择前10个cds的代码,后者又与请求相关艺术家的代码无关。

现在你可以说我可以将内部ORDER BY移动到OVER()子句中,但随后我打破了封装,因为我必须选择连接表的列,所以我可以稍后再按它们排序。另一个问题是在一个别名下合并两个表格;如果我在两个表中都有相同的命名列,则select me。*会在那里停止,并且列名称错误。

我愿意牺牲一些优化器性能,但2 ** 32对我来说似乎太过分了。所以我正在寻找中间立场。

4 个答案:

答案 0 :(得分:3)

  • 如果你想要me.id的顶行,只需在ROW_NUMBER的ORDER BY中询问。不要在子查询和TOP周围追逐你的尾巴。
  • 如果在连接表字段上有WHERE子句,则可以使用外部JOIN。所有外部字段都将为NULL并由WHERE过滤掉,因此实际上是内连接。

WITH cteRowNumbered AS (
  SELECT [me].id, [me].status 
  ROW_NUMBER() OVER (ORDER BY me.id ASC) AS rno__row__index 
  FROM [PurchaseOrders] [me]           
  JOIN [POLineItems] [line_items] ON [line_items].[id] = [me].[id]          
  WHERE [line_items].[part_id] = ?)
SELECT me.id, me.status 
FROM cteRowNumbered
WHERE rno__row__index BETWEEN 1 and 25

我使用CTE而不是子查询只是因为我发现它们更具可读性。

答案 1 :(得分:1)

使用:

SELECT x.*
  FROM (SELECT po.id, 
               po.status,
               ROW_NUMBER() OVER( ORDER BY po.id) AS rno__row__index
          FROM [PurchaseOrders] po
          JOIN [POLineItems] li ON li.id = po.id
         WHERE li.pat_id = ?) x
 WHERE x.rno__row__index BETWEEN 1 AND 25
ORDER BY po.id ASC

除非您为了简化示例而省略了细节,否则您所提供的内容中不需要所有子查询。

答案 2 :(得分:1)

感谢唯一一个通过反对的方式看到并在我们无法访问的大型桌子上尝试查询的人。对于所有其他人说这根本不起作用(将返回随机行) - 我们知道手册中说的是什么,我们知道这是一个黑客 - 这就是我们首先提出问题的原因。然而,在没有尝试的情况下彻底解雇查询是相当浅薄的。有人能为我们提供一个真实的例子(前面有CREATE / INSERT语句),证明上述查询有问题吗?

答案 3 :(得分:-1)

您的更新使事情变得更加清晰。我认为你使用的方法存在严重缺陷。尽管能够在应用程序中使用封装的,可重用的代码是很好的,但前端应用程序与数据库的动物大不相同。它们通常处理小型结构和针对这些结构的小型离散过程。另一方面,数据库通常处理以数百万行测量的表,有时甚至更多。使用相同的方法通常会导致代码执行起来非常糟糕,无法使用。即使它现在有效,它很可能不会扩展,并将导致重大问题。

祝你好运,但我认为除了最小的数据库外,这种方法不会很好。