如何加快 T-SQL 查询速度

发布于 2024-08-01 14:08:53 字数 1165 浏览 2 评论 0原文

我开发了几个 T-SQL 存储过程,用于迭代相当多的数据。 第一个需要几分钟的时间来运行一年多的数据,这对于我的目的来说是很好的。 第二个使用相同的结构/算法,尽管数据更多,但需要两个小时,这是难以忍受的。

我正在使用 SQL 服务器和查询分析器。 是否有任何分析工具?如果有,它们是如何工作的?

或者,根据下面的伪代码,对如何提高速度有什么想法? 简而言之,我使用游标来迭代来自直接 SELECT(来自几个连接表)的数据。 然后,我根据这些值构建一条 INSERT 语句,并将结果插入到另一个表中。 某些 SELECTed 变量在 INSERTion 之前需要进行一些操作。 其中包括从日期值中提取一些日期部分、一些基本的浮点运算和一些字符串连接。

--- 粗略算法/伪代码

DECLARE <necessary variables>
DECLARE @cmd varchar(1000)
DECLARE @insert varchar(100) = 'INSERT INTO MyTable COL1, COL2, ... COLN, VALUES('

DECLARE MyCursor Cursor FOR
    SELECT <columns> FROM TABLE_1 t1
    INNER JOIN TABLE_2 t2 on t1.key = t2.foreignKey
    INNER JOIN TABLE_3 t3 on t2.key = t3.foreignKey

OPEN MyCursor
FETCH NEXT FROM MyCursor INTO @VAL1, @VAL2, ..., @VALn
WHILE @@FETCH_STATUS = 0
BEGIN
   @F = @VAL2 / 1.1  --- float op
   @S = @VAL3 + ' ' + @VAL1
   SET @cmd = @insert
   SET @cmd = @cmd + DATEPART(@VAL1) + ', '
   SET @cmd = @cmd + STR(@F) + ', '
   SET @cmd = @cmd + @S + ', '
   SET @cmd = @cmd + ')'
   EXEC (@cmd)
   FETCH NEXT FROM MyCursor @VAL1, @VAL2, ..., @VALn
END
CLOSE MyCursor
DEALLOCATE MyCursor

I've developed a couple of T-SQL stored procedures that iterate over a fair bit of data. The first one takes a couple of minutes to run over a year's worth of data which is fine for my purposes. The second one, which uses the same structure/algorithm, albeit over more data, takes two hours, which is unbearable.

I'm using SQL-Server and Query-Analyzer. Are there any profiling tools, and, if so, how do they work?

Alternatively, any thoughts on how improve the speed, based on the pseudo-code below? In short, I use a cursor to iterate over the data from a straight-forward SELECT (from a few joined tables). Then I build an INSERT statement based on the values and INSERT the result into another table. Some of the SELECTed variables require a bit of manipulation before INSERTion. The includes extracting some date parts from a date value, some basic float operations and some string concatenation.

--- Rough algorithm / pseudo-code

DECLARE <necessary variables>
DECLARE @cmd varchar(1000)
DECLARE @insert varchar(100) = 'INSERT INTO MyTable COL1, COL2, ... COLN, VALUES('

DECLARE MyCursor Cursor FOR
    SELECT <columns> FROM TABLE_1 t1
    INNER JOIN TABLE_2 t2 on t1.key = t2.foreignKey
    INNER JOIN TABLE_3 t3 on t2.key = t3.foreignKey

OPEN MyCursor
FETCH NEXT FROM MyCursor INTO @VAL1, @VAL2, ..., @VALn
WHILE @@FETCH_STATUS = 0
BEGIN
   @F = @VAL2 / 1.1  --- float op
   @S = @VAL3 + ' ' + @VAL1
   SET @cmd = @insert
   SET @cmd = @cmd + DATEPART(@VAL1) + ', '
   SET @cmd = @cmd + STR(@F) + ', '
   SET @cmd = @cmd + @S + ', '
   SET @cmd = @cmd + ')'
   EXEC (@cmd)
   FETCH NEXT FROM MyCursor @VAL1, @VAL2, ..., @VALn
END
CLOSE MyCursor
DEALLOCATE MyCursor

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

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

发布评论

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

评论(5

捂风挽笑 2024-08-08 14:08:53

SQl Server 还附带了一个名为 SQL Server Profiler 的分析工具。 它是 SSMS 中工具下菜单上的第一个选择。

SQl Server also comes with a profiling tool called SQL Server Profiler. It's the first pick on the menu under Tools in SSMS.

挽容 2024-08-08 14:08:53

失去光标。 现在。 (请参阅此处了解原因:为什么在 SQL Server 中使用游标被认为是不好的做法吗?)。

毫不粗鲁地说,您似乎正在采用程序程序员的 SQL 方法,这几乎总是次优的。

如果您所做的事情很复杂并且您没有信心,我会分三个步骤进行:

1)使用 insert 或 select into 将核心数据选择到临时表中。

2)使用更新进行操作 - 您可能只需更新现有列即可执行此操作,或者您可能需要在创建临时表时以正确的格式添加一些额外的列。 如果需要,您可以使用多个更新语句进一步分解它。

3)将其选择到您想要的任何位置。

如果您想将其全部作为一个步骤调用,那么您可以将整个过程包装到一个存储过程中。

这使得调试变得容易,并且其他人在需要时也可以轻松合作。 您可以将更新分解为单独的步骤,以便快速确定出现问题的位置。

也就是说,从外观上看,我不相信您所做的事情不能在单个插入语句中完成。 它可能没有吸引力,但我相信它可以做到:

INSERT INTO NewTable
DATEPART(@VAL1) DateCol, 
@STR(@VAL2 / 1.1) FloatCol,
@VAL3 + ' ' + @VAL1 ConcatCol
FROM TABLE_1 t1
INNER JOIN TABLE_2 t2 on t1.key = t2.foreignKey
INNER JOIN TABLE_3 t3 on t2.key = t3.foreignKey

DateCol、FloatCol 和 ConcatCol 是您希望列具有的任何名称。 尽管不需要它们,但最好将它们分配为(a)它可以让您更清楚地了解您正在做什么以及(b)某些语言难以处理未命名的列(并以非常不清楚的方式处理它)。

Lose the cursor. Now. (See here for why: Why is it considered bad practice to use cursors in SQL Server?).

Without being rude you seem to be taking a procedural programmers approach to SQL which is pretty much always going to be sub-optimal.

If what you're doing is complex and you're not confident I'd do it in three steps:

1) Select of the core data into a temporary table using insert or select into.

2) Use update to do the manipulation - you may be able to do this just updating existing columns or you may need to have added a few extra ones in the right format when you create the temporary table. You can use multiple update statements to break it down further if you want.

3) Select it out into wherever you want it.

If you want to call it all as one step then you can then wrap the whole thing up into a stored procedure.

This makes it easy to debug and easy for someone else to work with if they need to. You can break your updates down into individual steps so you can quickly identify what's gone wrong where.

That said I don't believe that what you're doing can't be done in a single insert statement from the looks of it. It might not be attractive but I believe it could be done:

INSERT INTO NewTable
DATEPART(@VAL1) DateCol, 
@STR(@VAL2 / 1.1) FloatCol,
@VAL3 + ' ' + @VAL1 ConcatCol
FROM TABLE_1 t1
INNER JOIN TABLE_2 t2 on t1.key = t2.foreignKey
INNER JOIN TABLE_3 t3 on t2.key = t3.foreignKey

DateCol, FloatCol and ConcatCol are whatever names you want the columns to have. Although they're not needed it's best to assign them as (a) it makes it clearer what you're doing and (b) some languages struggle with unnamed columns (and handle it in a very unclear way).

谁对谁错谁最难过 2024-08-08 14:08:53

摆脱游标和动态sql:

INSERT INTO MyTable 
        (COL1, COL2, ... COLN)
    SELECT 
        <columns>
            ,DATEPART(@VAL1) AS DateCol
            ,@STR(@VAL2 / 1.1) AS FloatCol
            ,@VAL3 + ' ' + @VAL1 AS ConcatCol
        FROM TABLE_1        t1    
        INNER JOIN TABLE_2  t2 on t1.key = t2.foreignKey
        INNER JOIN TABLE_3  t3 on t2.key = t3.foreignKey

get rid of the cursor and dynamic sql:

INSERT INTO MyTable 
        (COL1, COL2, ... COLN)
    SELECT 
        <columns>
            ,DATEPART(@VAL1) AS DateCol
            ,@STR(@VAL2 / 1.1) AS FloatCol
            ,@VAL3 + ' ' + @VAL1 AS ConcatCol
        FROM TABLE_1        t1    
        INNER JOIN TABLE_2  t2 on t1.key = t2.foreignKey
        INNER JOIN TABLE_3  t3 on t2.key = t3.foreignKey
老街孤人 2024-08-08 14:08:53

是否有任何分析工具,如果
那么,它们是如何工作的呢?

要回答有关查询调优工具的问题,您可以使用 TOAD for SQL Server 来协助查询调优。

我真的很喜欢这个工具,因为它会以大约 20 种不同的方式运行您的 SQL 语句,并比较执行计划,以便您确定最佳的一种。 有时我会惊讶于它对我的语句的优化,而且效果非常好。

更重要的是,当我在未来编写的脚本中使用这些技巧时,我已经使用它成为了更好的 t-sql 编写者。 我不知道 TOAD 如何使用这个脚本,因为正如其他人提到的那样,它使用游标,而我不使用它们,所以从未尝试过优化它。

TOAD 是 SQL Server 功能的一个巨大工具箱,查询优化只是其中的一小部分。 顺便说一句,我与 Quest Software 没有任何关系。

Are there any profiling tools, and, if
so, how do they work?

To answer your question regarding query tuning tools, you can use TOAD for SQL Server to assist in query tuning.

I really like this tool as it will run your SQL statement something like 20 different ways and compare execution plans for you to determine the best one. Sometimes I'm amazed at what it does to optimize my statements, and it works quite well.

More importantly, I've used it to become a better t-sql writer as I use the tips on future scripts that I write. I don't know how TOAD would work with this script because as others have mentioned it uses a cursor, and I don't use them so have never tried to optimize one.

TOAD is a huge toolbox of SQL Server functionality, and query optimization is only a small part. Incidentally, I am not affiliated with Quest Software in any way.

烂柯人 2024-08-08 14:08:53

首先要做的事情 - 摆脱游标...

INSERT INTO MyTable COL1, COL2, ... , COLN
SELECT ...cols and manipulations...
FROM TABLE_1 t1
INNER JOIN TABLE_2 t2 on t1.key = t2.foreignKey
INNER JOIN TABLE_3 t3 on t2.key = t3.foreignKey

大多数事情应该可以直接在 TSQL 中实现(没有示例很难确定) - 并且您可以考虑使用 UDF 来进行更复杂的操作。

The first thing to do - get rid of the cursor...

INSERT INTO MyTable COL1, COL2, ... , COLN
SELECT ...cols and manipulations...
FROM TABLE_1 t1
INNER JOIN TABLE_2 t2 on t1.key = t2.foreignKey
INNER JOIN TABLE_3 t3 on t2.key = t3.foreignKey

Most things should be possible direct in TSQL (it is hard to be definite without an example) - and you could consider a UDF for more complex operations.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文