使用 order by 时的动态 order by - 加速

发布于 2024-12-21 10:41:03 字数 495 浏览 5 评论 0原文

我正在使用行号从存储过程获取分页结果。

我发现使用动态 case 语句列名称进行排序会减慢速度 - 但如果我按一切硬编码顺序就可以了。

有没有一种方法可以通过不使整个 sql 查询成为一个字符串并使用 SP_EXECUTESQL 来加速动态排序

            ROW_NUMBER() OVER (ORDER BY 
            CASE WHEN @OrderByColumnName = 'IdentityValue' AND @OrderAscending  = 0 THEN CLH.IdentityValue END DESC,
            CASE WHEN @OrderByColumnName = 'IdentityValue' AND @OrderAscending  = 1 THEN CLH.IdentityValue END
            --CLH.CustomerName

            ) AS [ROW]

I am using row number to get paged results back from a stored procedure.

I am finding that ordering using a dynamic case statement column name is slowing things down - but if I hardcode the order by everything is ok.

Is there a way to speed up the dynamic order by without making the WHOLE sql query one string and using SP_EXECUTESQL

            ROW_NUMBER() OVER (ORDER BY 
            CASE WHEN @OrderByColumnName = 'IdentityValue' AND @OrderAscending  = 0 THEN CLH.IdentityValue END DESC,
            CASE WHEN @OrderByColumnName = 'IdentityValue' AND @OrderAscending  = 1 THEN CLH.IdentityValue END
            --CLH.CustomerName

            ) AS [ROW]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

挽袖吟 2024-12-28 10:41:03

问题在于 SQL Server 正在尝试构建一个执行计划来适应所有参数。这意味着当您给它不同的参数时,它不会改变主意并选择不同的索引。 (不同索引部分很重要,因为对不适当的索引重新排序的负载可能非常高。)

实现这种情况的唯一方法是生成新的执行计划,这涉及动态 SQL - 这正是您想要避免的。

但是;动态 SQL 和 SP_EXECUTESQL 不一定是坏主意。由于它也可以参数化,正确使用确实允许执行计划重用,并且可以非常有效地解决此类问题。

是否有特定原因需要避免动态 SQL?

唯一实际的解决办法是多次以不同的顺序编写查询,然后选择与 T 一起使用的查询-SQL IF 块。这将允许优化器生成不同的执行计划。

The problem is that SQL Server is trying to build ONE execution plan to fit all parameters. This means that it doesn't change it's mind and pick a different index when you give it different parameters. (The different index part is important as the load of re-ordering an inappropriate index can be very high.)

The only way for that to happen is to generate a new execution plan, and that involves dynamic SQL - Exactly what you want to avoid.

However; dynamic SQL and SP_EXECUTESQL is not necessarily a bad idea. As it can also be parametrised, correct use does allow execution plan re-use and can be exceptionally efficient at these kinds of problems.

Is there specific reason that you need to avoid dynamic SQL?

The only realistic work around is to have the query written out multiple times, with the different ordering, and pick which one to use with T-SQL IF blocks. This will allow the optimiser to generate the varying execution plans.

末骤雨初歇 2024-12-28 10:41:03

SQL Server 不支持单个查询根据参数值使用不同的索引。 AFAIK,有两种解决方案:

  • 在存储过程中构建动态查询并使用 sp_executesql
  • 构建动态查询客户端

在实践中,PHP 和 .NET 应用程序很难共享代码。或者甚至针对不同的 .NET 版本。这使得第一个选项成为更强的选择。

因此,最好的方法是使用动态 SQL。是的,这非常令人惊讶。 :)

Having a single query use different indexes based on parameter values is not supported in SQL Server. AFAIK, there are two solutions to this:

  • Build a dynamic query in a stored procedure and use sp_executesql
  • Build a dynamic query client side

In practice, it's hard for a PHP and a .NET application to share code. Or even for different .NET versions. That makes the first option the stronger choice.

So the best way to do this involves dynamic SQL. And yeah that's pretty surprising. :)

就是爱搞怪 2024-12-28 10:41:03

您可以尝试的一件事是将两个 case 子句合并为一个 case - 像这样:

(ORDER BY 
        CASE WHEN @OrderByColumnName = 'IdentityValue' AND @OrderAscending  = 0 
                 THEN CLH.IdentityValue*-1
             WHEN @OrderByColumnName = 'IdentityValue' AND @OrderAscending  = 1 
                 THEN CLH.IdentityValue 
        END
 )

显然,如果某些潜在的排序值是字符串而不是数字,则这种方法不实用。

One thing you could try would be to combine your two case clauses into a single case - like this:

(ORDER BY 
        CASE WHEN @OrderByColumnName = 'IdentityValue' AND @OrderAscending  = 0 
                 THEN CLH.IdentityValue*-1
             WHEN @OrderByColumnName = 'IdentityValue' AND @OrderAscending  = 1 
                 THEN CLH.IdentityValue 
        END
 )

Obviously, this approach would not be practical if some of your potential sort values are strings instead of numbers.

丢了幸福的猪 2024-12-28 10:41:03

尝试多个 ROW_NUMBER 语句,以便减少每次排序的处理量

   ROW_NUMBER() OVER (ORDER BY CLH.IdentityValue) DESC AS rnDesc,
   ROW_NUMBER() OVER (ORDER BY CLH.IdentityValue) AS rnAscDesc,
   ...
ORDER BY
   CASE WHEN @OrderByColumnName = 'IdentityValue' AND @OrderAscending  = 0 THEN rnDesc END,
   CASE WHEN @OrderByColumnName = 'IdentityValue' AND @OrderAscending  = 1 THEN rnDesc END

Try multiple ROW_NUMBER statements so you have less processing per sort

   ROW_NUMBER() OVER (ORDER BY CLH.IdentityValue) DESC AS rnDesc,
   ROW_NUMBER() OVER (ORDER BY CLH.IdentityValue) AS rnAscDesc,
   ...
ORDER BY
   CASE WHEN @OrderByColumnName = 'IdentityValue' AND @OrderAscending  = 0 THEN rnDesc END,
   CASE WHEN @OrderByColumnName = 'IdentityValue' AND @OrderAscending  = 1 THEN rnDesc END
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文