【问题标题】:ALTER INDEX using while Loop in SQL Server在 SQL Server 中使用 while 循环更改索引
【发布时间】:2020-11-11 20:16:41
【问题描述】:

我正在尝试使用 while 循环 ALTER 索引。

以下代码获取所有大于 30% 分片的 INDEX STATEMENTS。存储到 TEMP 表中。

我正在尝试使用 while 循环进行迭代并执行每个 ALTER STATEMENT。

注意:我不想使用光标。

WITH resultset AS
(
    SELECT
        DB_NAME() AS 'DB Name',
        dbtables.[name] AS 'Table Name',
        dbindexes.[name] AS 'Index Name',
        indexstats.avg_fragmentation_in_percent as '% Fragmented',
        indexstats.page_count as 'Page Count',
        'Query' = case when avg_fragmentation_in_percent between 10 and 29.99 then 'ALTER INDEX '+dbindexes.[name] +' ON '+dbtables.[name]+' REBUILD'
when avg_fragmentation_in_percent  >= 30 then 'ALTER INDEX '+dbindexes.[name] +' ON '+dbtables.[name]+' REBUILD' end
    FROM 
        sys.DM_DB_INDEX_PHYSICAL_STATS(DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
    INNER JOIN 
        sys.tables dbtables ON dbtables.[object_id] = indexstats.[object_id]
    INNER JOIN 
        sys.schemas dbschemas ON dbtables.[schema_id] = dbschemas.[schema_id]
    INNER JOIN 
        sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id]
                                 AND indexstats.index_id = dbindexes.index_id
     WHERE 
         dbindexes.name IS NOT NULL
         AND dbtables.Temporal_type <> 1
         AND indexstats.avg_fragmentation_in_percent >= 30
)
SELECT * 
INTO #FragmentationTable 
FROM resultset

DECLARE @ROWCOUNT INT
DECLARE @execute  nvarchar(500)
SELECT @ROWCOUNT= COUNT(1)  FROM #FragmentationTable
SELECT @ROWCOUNT

DECLARE @cnt INT = 0 ;

WHILE @cnt < @ROWCOUNT
BEGIN
   select @execute=query  from #FragmentationTable
    --EXEC sp_executesql @execute
    print @execute
    SET @cnt = @cnt + 1;
END;
PRINT 'THIS IS OUTSIDE OF THE LOOP'
DROP TABLE #FragmentationTable

输出是这样的。它只改变一个索引。

【问题讨论】:

  • 您为什么希望select @execute=query from #FragmentationTable 每次都返回不同的行?您必须以某种方式告诉 SQL Server 您已经处理了“第一”行,以便它移动到第二行(您需要一个行号来识别 next 行,或删除您刚刚处理的行)。或者,与其构建 80 个命令并将它们填充到一个表中,一次执行一个,为什么不构建一组 80 个命令并执行一次呢?
  • 提示:将对象名称组装成动态 SQL 语句的最佳实践是使用 QuoteName() 以避免出现奇怪名称的问题,例如New Table 带有空格或保留字,例如 From

标签: sql-server azure tsql indexing


【解决方案1】:

如果要遍历表,请使用游标。这就是他们的目的。

在构造动态 SQL 时,始终使用 QUOTENAME 函数转义对象名称。例如

WITH resultset AS
(
    SELECT
        DB_NAME() AS 'DB Name',
        dbtables.[name] AS 'Table Name',
        dbindexes.[name] AS 'Index Name',
        indexstats.avg_fragmentation_in_percent as '% Fragmented',
        indexstats.page_count as 'Page Count',
        'Query' = case when avg_fragmentation_in_percent between 10 and 29.99 then 'ALTER INDEX '+quotename(dbindexes.[name]) +' ON '+quotename(dbtables.[name])+' REBUILD'
when avg_fragmentation_in_percent  >= 30 then 'ALTER INDEX '+quotename(dbindexes.[name]) +' ON '+quotename(dbtables.[name])+' REBUILD' end
    FROM 
        sys.DM_DB_INDEX_PHYSICAL_STATS(DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
    INNER JOIN 
        sys.tables dbtables ON dbtables.[object_id] = indexstats.[object_id]
    INNER JOIN 
        sys.schemas dbschemas ON dbtables.[schema_id] = dbschemas.[schema_id]
    INNER JOIN 
        sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id]
                                 AND indexstats.index_id = dbindexes.index_id
     WHERE 
         dbindexes.name IS NOT NULL
         AND dbtables.Temporal_type <> 1
         AND indexstats.avg_fragmentation_in_percent >= 30
)
SELECT * 
INTO #FragmentationTable 
FROM resultset

declare c cursor local for 
  select query
  from #FragmentationTable

declare @sql nvarchar(max)

open c
fetch next from c into @sql
WHILE @@FETCH_STATUS = 0
BEGIN
    --EXEC sp_executesql @sql
    print @sql
    fetch next from c into @sql
END;
close c;
deallocate c;
PRINT 'THIS IS OUTSIDE OF THE LOOP'
DROP TABLE #FragmentationTable

【讨论】:

    猜你喜欢
    • 2014-02-10
    • 1970-01-01
    • 2020-03-01
    • 1970-01-01
    • 2018-10-28
    • 2020-10-10
    • 2013-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多