2014-02-05 70 views
0

我想運行一個SQL腳本,它將在我的每個數據庫上創建一個函數,然後使用該函數填充一個臨時表,然後將其用作源另一個用於重建索引的遊標。然而,我遇到的問題是該函數只能在我當前連接的數據庫上創建,即使我正在使用我的光標中的「使用數據庫」。我已經複製了下面的腳本,這是爲了隔離問題而寫的(所以它還沒有效率)。反對所有數據庫中執行腳本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 
[email protected]_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

最好的辦法是使用微軟的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 
0

每個sp_executesql的是根據它自己的情況下運行,因此sp_executesql的@Command只把它的調用作爲使用其他數據庫。

嘗試將'USE ' + @DB轉換成@Create_Function