如何加快T-SQL查询速度?

时间:2009-08-10 11:37:15

标签: sql-server tsql optimization profiling

我开发了几个T-SQL存储过程,它们迭代了相当多的数据。第一个需要花费几分钟来运行一年的数据,这对我的目的来说很好。第二个使用相同的结构/算法,虽然数据量更多,需要两个小时,这是无法忍受的。

我正在使用SQL-Server和Query-Analyzer。是否有任何分析工具,如果有,它们如何工作?

或者,根据下面的伪代码,有关如何提高速度的任何想法?简而言之,我使用游标迭代来自直接SELECT(来自几个连接表)的数据。然后我根据值构建一个INSERT语句,并将结果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

5 个答案:

答案 0 :(得分:11)

要做的第一件事 - 摆脱光标......

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进行更复杂的操作。

答案 1 :(得分:5)

丢失光标。现在。 (请参阅此处了解原因:Why is it considered bad practice to use cursors in SQL Server?)。

没有粗鲁,你似乎采用程序员程序员的SQL方法,这几乎总是不太理想。

如果您正在做的事情很复杂而且您不自信我会分三步完成:

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

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

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)某些语言与未命名的列斗争(并以非常不明确的方式处理它)。

答案 2 :(得分:0)

摆脱游标和动态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

答案 3 :(得分:0)

  

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

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

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

更重要的是,我使用它来成为一个更好的t-sql编写器,因为我使用了我编写的未来脚本的提示。我不知道TOAD如何使用这个脚本,因为正如其他人提到它使用光标,我不使用它们所以从来没有试过优化它。

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

答案 4 :(得分:0)

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