【问题标题】:How to optimize this query using cursor?如何使用游标优化此查询?
【发布时间】:2011-09-24 22:08:17
【问题描述】:
DECLARE tableList CURSOR FOR    
    SELECT  t.name 
    FROM sys.tables t
        INNER JOIN sys.columns c
        ON t.object_id = c.object_id
    WHERE
            t.name NOT LIKE 'z%'
        AND t.name NOT LIKE '%delete%'
        AND t.name <> 'tblUsers'
        AND t.name <> 'tblUserLogins'
        AND t.name <> 'searchR'
        AND t.name <> 'tblUserPortfolio'
        AND t.name <> 'alerts_User'
        AND c.name LIKE 'userid'
        OR  c.name LIKE 'user_id'
    ORDER BY name
OPEN tableList
FETCH NEXT FROM tableList
INTO @tablename

上面是构建游标的查询,它使用了很多LIKENOT LIKE 操作,我认为这些操作运行起来可能很昂贵。

所以我想问是否有更好的方法来构建查询而不使用太多LIKE/NOT LIKE 并使其更优化。

谢谢。

编辑:

这里使用游标的目的是Loop Through所有匹配的表,这样我们就可以动态地插入/更新/删除记录。

我正在使用的数据库中有150多个表,所以我认为sql server还不如做脏活。

【问题讨论】:

  • 我怀疑这里真正的问题是CURSOR,而不是查询...另外:不要假设它们很贵;尤其是在 sys.tables 和 sys.columns 上,其中的行量不会太大
  • 最后两个条件(与OR结合)可能应该放在括号中,否则最后一个会丢弃所有以前的AND条件。

标签: sql sql-server tsql optimization stored-procedures


【解决方案1】:

我愿意:

1) 通过使用 NOT IN 而不是多个 "... 和 t.name ..."
使 SQL 更具可读性 (IMO) 2) 将 c.name LIKEs 更改为单个 IN 子句,因为您似乎想要完全匹配,而不需要 LIKE

SELECT  t.name 
FROM sys.tables t
    INNER JOIN sys.columns c ON t.object_id = c.object_id
WHERE t.name NOT LIKE 'z%' AND t.name NOT LIKE  '%delete%' 
    AND t.name NOT IN  ('tblUsers','tblUserLogins','searchR','tblUserPortfolio','alerts_User')
    AND c.name IN ('userid','user_id') 
ORDER BY name

这实际上不太可能在性能方面产生大量不同的 tbh,但我认为它更具可读性/可维护性。

但是,我要提出的主要观点是您是否真的需要一个光标 - 我肯定会考虑删除它以支持基于集合的方法。虽然需要知道您在光标中正在做什么才能提出替代方案。

编辑: 您可以尝试这种动态生成 SQL 并一次性执行的方法(简单示例,假设您想将相同的行插入每个具有相同结构的表中)。很难知道这是否真的适合您的确切场景(或者它是否真的会产生有价值的差异),但了解这种技术可能很有用。

DECLARE @nSQL NVARCHAR(MAX)
SELECT @nSQL = COALESCE(@nSQL, '')  + 
'INSERT ' + QUOTENAME(t.name) + '([SomeCol]) VALUES (@ValueToInsert);' + CHAR(10)
FROM sys.tables t
    INNER JOIN sys.columns c ON....
...{rest of current SELECT)

-- comment out PRINT, and uncomment EXECUTE statement to actually run the SQL
PRINT @nSQL
-- EXECUTE sp_executesql @nSQL, N'@ValueToInsert VARCHAR(10)', 'NewValue'

【讨论】:

  • +1 获取有关删除光标的好建议。但可读性是相对的。您的更改不会使其不再具有可读性,因为它的长度与原来的长度大致相同。类似长度查询的可读性是通过缩进实现的。我重新格式化了 OPs 查询以使其更具可读性,并且它也显示了一个可能的缺陷(您使用单个 x IN (...) 进行了更正。
  • 我已经更新了这个问题,简要解释了为什么我想在这里使用光标。感谢您再次查看。
猜你喜欢
  • 2016-02-11
  • 1970-01-01
  • 2016-07-22
  • 2022-07-21
  • 2017-03-01
  • 2023-04-02
  • 1970-01-01
相关资源
最近更新 更多