我正在尝试运行一个SQL脚本,它将在我的每个数据库上创建一个函数,然后使用该函数填充临时表,然后将其用作另一个用于重建索引的游标的源。但是,我遇到的问题是该函数只能在我当前连接的数据库上创建,即使我在游标中使用“使用数据库”。我已经复制了下面的脚本,该脚本是为了隔离问题而编写的(所以它还没有效率)。
IF OBJECT_ID (N'sp_index_maintenance', N'P') IS NOT NULL
DROP Proc sp_index_maintenance;
GO
Create proc sp_index_maintenance
AS
BEGIN
CREATE TABLE #T1
(
Database_Name NVARCHAR(MAX),
[Object_Name] NVARCHAR(MAX),
Index_Name NVARCHAR(MAX),
Index_ID INT,
Index_Type_Desc NVARCHAR(MAX),
AVG_Fragmentation_in_percent INT,
Fragment_Count INT,
Page_Count INT
)
DECLARE @DB as nvarchar(100);
DECLARE @Command as NVARCHAR(MAX);
DECLARE @FetchFragStatus AS NVARCHAR(max);
DECLARE @Create_Function NVARCHAR(Max);
DECLARE @Drop_Function NVARCHAR(MAX);
DECLARE DB_USE cursor for
SELECT [Name] FROM sys.databases
OPEN DB_USE
FETCH NEXT FROM DB_USE
INTO @DB
WHILE @@FETCH_STATUS = 0
BEGIN
SET @Command = 'USE ' + @DB
SET @Drop_Function = 'USE ' + @DB + ' IF OBJECT_ID (N''dbo.Index_fragmentation'', N''IF'') IS NOT NULL
DROP Function dbo.index_fragmentation'
SET @Create_Function =
'Create function dbo.index_fragmentation()
RETURNS TABLE AS
RETURN
(
SELECT
DB_NAME(database_ID) AS Database_Name,
OBJECT_NAME(ps.object_id) as [Object_Name],
i.Name AS Index_Name,
ps.index_id,
index_type_desc,
avg_fragmentation_in_percent,
fragment_count,
page_count
FROM
sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, ''Limited'') AS ps
INNER JOIN
sys.indexes AS i WITH (NOLOCK)
ON ps.[object_id] = i.[object_id]
AND ps.index_id = i.index_id
WHERE database_id = DB_ID()
--AND page_count > 500
AND avg_fragmentation_in_percent >= 20)'
PRINT (@command)
EXEC sp_executesql @Command
--PRINT (@Drop_Function)
--EXEC (@Drop_Function)
PRINT (@Create_function)
EXEC sp_executesql @Create_function
FETCH NEXT FROM DB_USE
INTO @DB
END
CLOSE DB_USE
DEALLOCATE DB_USE
DECLARE DB_USE cursor for
SELECT [Name] FROM sys.databases
OPEN DB_USE
FETCH NEXT FROM DB_USE
INTO @DB
WHILE @@FETCH_STATUS = 0
BEGIN
SET @FetchFragStatus = 'USE ' + @DB +
' INSERT INTO #T1 (Database_Name, Object_Name, Index_Name, index_Id, index_type_desc, avg_fragmentation_in_percent, fragment_count, page_count)
SELECT * FROM dbo.Index_Fragmentation()'
PRINT (@FetchFragStatus);
EXEC (@FetchFragStatus);
FETCH NEXT FROM DB_USE
INTO @DB
END
CLOSE DB_USE
DEALLOCATE DB_USE
--DECLARE @DB_Name NVARCHAR(100);
--DECLARE @Index_Name NVARCHAR(100);
--DECLARE @Alter_index NVARCHAR(MAX);
--DECLARE @Obj_Name NVARCHAR(MAX);
--
--DECLARE Fragmented_index_Cur Cursor For
--SELECT Database_Name, Index_Name, [Object_Name]
--FROM #T1
--
--OPEN Fragmented_index_cur
--FETCH NEXT FROM Fragmented_index_cur
--INTO
--@DB_Name, @Index_Name, @Obj_Name
--WHILE @@FETCH_STATUS = 0
--BEGIN
--SET @Command = 'USE ' + @DB_NAME
--SET @Alter_index = 'ALTER Index ' + @Index_Name + ' ON ' + @Obj_Name + ' REBUILD;'
--PRINT (@command)
--EXEC (@command)
--PRINT (@Alter_Index)
--EXEC (@Alter_index)
--
--FETCH NEXT FROM Fragmented_index_cur
--INTO @DB_Name, @Index_Name, @Obj_Name
--
--END
--CLOSE Fragmented_index_cur
--DEALLOCATE Fragmented_index_cur
SELECT * FROM #T1
RETURN;
END
EXEC sp_index_maintenance
答案 0 :(得分:0)
针对所有数据库执行脚本的最佳方法是使用Microsoft的EXEC sys.sp_MSforeachdb
未记录的功能,这非常方便,如果你谷歌你可以找到很多使用它的例子。通过使用此功能,您可以摆脱社区中的许多人将惩罚您的坏游标。我只需要知道何时使用它们就可以使用游标。
这是您的查询的简化版本。这将在所有数据库中获取错误索引并存储到临时表中。
CREATE PROCEDURE myBadIndexFromAllDBs
AS
BEGIN
CREATE TABLE #tempTable
(
Database_Name VARCHAR(250)
,OBJECT_NAME VARCHAR(250)
,Index_Name VARCHAR(250)
,Index_id INT
,index_type_desc VARCHAR(60)
,avg_fragmentation_in_percent FLOAT
,fragment_count BIGINT
,page_count BIGINT
)
EXEC sys.sp_MSforeachdb
'
use [?]
INSERT INTO #tempTable
SELECT DB_NAME(database_ID) AS Database_Name
,OBJECT_NAME(ps.object_id) AS [Object_Name]
,i.Name AS Index_Name
,ps.index_id
,index_type_desc
,avg_fragmentation_in_percent
,fragment_count
,page_count
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, ''Limited'') AS ps
INNER JOIN sys.indexes AS i WITH ( NOLOCK )
ON ps.[object_id] = i.[object_id]
AND ps.index_id = i.index_id
WHERE database_id = DB_ID()
AND avg_fragmentation_in_percent >= 50
'
SELECT *
FROM #tempTable
END
答案 1 :(得分:0)
每个sp_executesql都在它自己的实例下运行,因此sp_executesql @Command只将其调用视为使用其他数据库。
尝试将'USE ' + @DB
移至@Create_Function