Sql-Server

無法刪除沒有關聯文件的文件組

  • August 2, 2018

我在 SQL Server 2017 CU3 上遇到了一些奇怪的錯誤消息。我正在遷移數據庫並重新組織文件組。“重組”是指我使用儲存過程在新文件組上為對象創建分區函式和分區方案,在分區時重建索引,然後刪除分區。

最後我得到了一些空文件組。他們的文件刪除。文件組本身也被刪除。這在大多數情況下都很有效。但是對於兩個數據庫,我刪除了文件…**留下一個文件組,**但沒有關聯文件

ALTER DATABASE REMOVE FILEGROUP

引發錯誤 5042:

無法刪除文件組“xyz”,因為它不為空。

我怎樣才能擺脫那個空文件組……可能是什麼問題?

我已經閱讀了一些常見問題,但它們在我的系統中不存在:

  • 檢查:
SELECT * FROM sys.partition_schemes;
SELECT * FROM sys.partition_functions;

0 行…數據庫中沒有剩餘分區對象

  • UPDATE STATISTICS對於數據庫中的所有對象

沒有效果

  • 檢查文件組上的索引:
SELECT * FROM  sys.data_spaces ds
INNER JOIN sys.indexes i
ON ds.data_space_id = i.data_space_id
WHERE ds.name = 'xyz'

0 行

  • 檢查文件組中的對象:
SELECT
   au.*,
   ds.name AS [data_space_name],
   ds.type AS [data_space_type],
   p.rows,
   o.name AS [object_name]
FROM sys.allocation_units au
   INNER JOIN sys.data_spaces ds
       ON au.data_space_id = ds.data_space_id
   INNER JOIN sys.partitions p
       ON au.container_id = p.partition_id
   INNER JOIN sys.objects o
       ON p.object_id = o.object_id
WHERE au.type_desc = 'LOB_DATA'
AND ds.name ='xyz'

0 行

在從文件組中刪除文件之前,我還嘗試了DBCC SHRINKFILE參數。EMPTYFILE這對我來說真的沒有意義,但是我閱讀了將其描述為修復的解決方案。反正沒有效果。


我有一些希望閱讀有關伺服器故障的這個問題並嘗試了以下方法:

  • 更新所有統計資訊
  • 刪除所有與索引無關的統計資訊

然而,這沒有任何效果。我仍然有一個沒有關聯文件的文件組,並且無法刪除該文件組。我完全感到困惑,因為這發生在某些數據庫中而不是其他數據庫中(具有相同的結構)。當我DBCC CHECK FILEGROUP在這個空文件組上執行時,我收到一堆錯誤消息,如下所示:

無法處理對象“STORY_TRANSLATIONSCCC”(ID 120387498)、索引“Ref90159CCC”(ID 2)的行集 ID 72057594712162304,因為它位於未檢查的文件組“CCC_APPLICATION_new”(ID 8)上。

“STORY_TRANSLATIONSCCC”的 DBCC 結果。對象“STORY_TRANSLATIONSCCC”的 0 頁中有 0 行。

這是正常的還是它指向不尋常的事情?

這個問題可能是重複的,但是我在 dba.stackexchange 上的其他問題中找不到適合我的解決方法。請查看我已經嘗試過的列表。這與無法刪除未使用的文件組中描述的解決方案相同。

更多細節

也許它有助於理解我在錯誤發生之前做了什麼。我正在計劃遷移到新伺服器。我目前正在測試實例上對此進行測試。數據庫從 prod 伺服器恢復,恢復模式切換為簡單。我的目標是重組文件組並從每個文件組一個文件的模型轉移到每個文件組兩個文件的模型。為了實現這一點,我創建了新的空文件組,每個文件組有兩個文件,然後將數據移過來。不幸的是,大多數對像都有 LOB 數據(XML 和二進制)……所以我也利用分區作為幫助來移動 lob 數據。最後,所有數據都駐留在新文件組中,舊文件組為空。然後我刪除所有文件並刪除相應的文件組。主文件組仍然存在,只是添加了另一個文件。我的問題。此過程工作正常,但在兩個數據庫中可以刪除文件,但不能刪除文件組。令人驚訝的是,這些數據庫的結構應該與其他數據庫的結構相同,在移動數據和刪除舊文件組的過程中沒有遇到任何問題。

因此,這是出現問題的兩個數據庫的文件組和文件的列表:

  1. CCC_GENTE

+-----------------+------------+
| Filegroup       | Filename   |
+-----------------+------------+
| CCC_APPLICATION | CCC_APP    |
+-----------------+------------+
| CCC_ARCHIVE     | CCC_ARCHIV |
+-----------------+------------+
| CCC_AXN         | CCC_AXN    |
+-----------------+------------+
| CCC_GDV         | CCC_GDV    |
+-----------------+------------+
| PRIMARY         | CCC        |
+-----------------+------------+

   +-----------------+--------------------------+--------------------+----------------------------------------------------+
| Filegroup name  | Filegroup temporary name | Filename (logical) | Status                                             |
+-----------------+--------------------------+--------------------+----------------------------------------------------+
| CCC_APPLICATION | -                        | CCC_APP            | file removed, filegroup  cannot be removed (error) |
+-----------------+--------------------------+--------------------+----------------------------------------------------+
| CCC_ARCHIVE     | -                        | CCC_ARCHIV         | file and filegroup removed                         |
+-----------------+--------------------------+--------------------+----------------------------------------------------+
| CCC_AXN         | -                        | CCC_AXN            | file and filegroup removed                         |
+-----------------+--------------------------+--------------------+----------------------------------------------------+
| CCC_GDV         | -                        | CCC_GDV            | file and filegroup removed                         |
+-----------------+--------------------------+--------------------+----------------------------------------------------+
| PRIMARY         | -                        | CCC                | file renamed to PRIMARY_1                          |
+-----------------+--------------------------+--------------------+----------------------------------------------------+
| PRIMARY         | -                        | PRIMARY_2          | new file added                                     |
+-----------------+--------------------------+--------------------+----------------------------------------------------+
| CCC_APPLICATION | CCC_APPLICATION_new      | CCC_APPLICATION_1  | new filegroup renamed at the end                   |
+-----------------+--------------------------+--------------------+----------------------------------------------------+
| CCC_APPLICATION | CCC_APPLICATION_new      | CCC_APPLICATION_2  | new filegroup renamed at the end                   |
+-----------------+--------------------------+--------------------+----------------------------------------------------+
| CCC_ARCHIVE     | CCC_ARCHIVE_new          | CCC_ARCHIVE_1      | new filegroup renamed at the end                   |
+-----------------+--------------------------+--------------------+----------------------------------------------------+
| CCC_ARCHIVE     | CCC_ARCHIVE_new          | CCC_ARCHIVE_2      | new filegroup renamed at the end                   |
+-----------------+--------------------------+--------------------+----------------------------------------------------+
| CCC_AXN         | CCC_AXN_new              | CCC_AXN_1          | new filegroup renamed at the end                   |
+-----------------+--------------------------+--------------------+----------------------------------------------------+
| CCC_AXN         | CCC_AXN_new              | CCC_AXN_2          | new filegroup renamed at the end                   |
+-----------------+--------------------------+--------------------+----------------------------------------------------+
| CCC_GDV         | CCC_GDV_new              | CCC_GDV_1          | new filegroup renamed at the end                   |
+-----------------+--------------------------+--------------------+----------------------------------------------------+
| CCC_GDV         | CCC_GDV_new              | CCC_GDV_2          | new filegroup renamed at the end                   |
+-----------------+--------------------------+--------------------+----------------------------------------------------+

我希望這會有所幫助。還有第二個數據庫,其中文件組名稱不同,但為簡潔起見,我將其省略。

四個月後,Microsoft 支持人員找到了解決方案。確實有一個表引用了這個大概是空的文件組。

該表由以下語句標識:

SELECT t.[name] FROM sys.tables t
  inner join sys.filegroups f
        on t.lob_data_space_id = f.data_space_id
  where f.name = 'xyz'

將數據移至新表並刪除有問題的表後,文件組已成功刪除。移動數據的過程是:創建一個具有相同結構和索引的新表,通過 SELECT INTO 複製數據,刪除舊表,重命名新表(當然,如果整個過程中有外鍵,請注意) )

仔細檢查數據庫中的文件組

通過發出以下命令驗證文件組沒有任何附加文件:

use [DB]
go
sp_helpfilegroup 

這將產生一個文件組列表:

groupname | groupid | filecount
-----------+---------+-----------
PRIMARY   | 1       | 1
xyz       | 2       | 1

…然後對於列出的每個文件組執行

use [DB]
go
sp_helpfilegroup @filegroupname='PRIMARY'
go
sp_helpfilegroup @filegroupname='xyz'

輸出可能如下所示:

groupname | groupid | filecount
-----------+---------+------------
xyz       | 2       | 1

….第二個輸出可能是:

 file_in_group    | fileid | filename                          | size    | maxsize   | growth  
------------------+--------+-----------------------------------+---------+-----------+---------
 xyz_logical_name | 3      | X:\SQL\SQL_DATA\xyz_filegroup.ndf | 5120 KB | Unlimited | 1024 KB  

刪除文件組

如果您仍然有一個與您的文件組之一關聯的文件,那麼刪除文件組的邏輯文件和文件組本身的完整命令將是:

USE [DB]
GO
ALTER DATABASE [DB] REMOVE FILE [xyz_logical_name]
GO
ALTER DATABASE [DB] REMOVE FILEGROUP [xyz]
GO

文件組“xyz”是預設值

如果您在嘗試刪除文件組的邏輯文件時收到如下所示的錯誤消息:

Msg 5031, Level 16, State 1, Line 88
Cannot remove the file 'xyz_logical_name' because it is the only file in the DEFAULT filegroup.

…那麼您必須將文件組設置為PRIMARY文件DEFAULT組:

ALTER DATABASE [DB] MODIFY FILEGROUP [PRIMARY] DEFAULT

文件組“xyz”是只讀的

但是,如果錯誤消息如下:

Msg 5055, Level 16, State 2, Line 88 
Cannot add, remove, or modify file 'xyz_logical_name'. The file is read-only.

…那麼您將不得不刪除xyz文件組上的 READ_ONLY 屬性:

ALTER DATABASE [DB] MODIFY FILEGROUP [xyz] READWRITE

您現在應該能夠刪除文件組的邏輯文件和文件組本身。

未結交易

如果您確實沒有與xyz您要刪除的文件組關聯的文件 (logical_name / pyhsical_file_name),那麼執行事務日誌備份可能會釋放任何阻礙進一步刪除文件組的事務。

撥打 911

如果一切都失敗了,您可能需要考慮與 Microsoft 通話。


元數據不匹配

進一步研究後添加

顯然,在某些情況下,數據庫中的元數據不能反映對象的實際位置。

參考:

這兩種情況似乎分別通過SQL Server 2014 SP1 的累積更新 3SQL Server 2016 的累積更新 1得到解決。它們不適用於您的情況,但它們表明有時元數據可能是錯誤的。

似乎阻止您的文件組刪除的項目是索引,它可能儲存有錯誤的元數據。

可能的解決方案

考慮重建Ref90159CCC錯誤消息中引用的索引。

Cannot process rowset ID 72057594712162304 of object 
"STORY_TRANSLATIONSCCC" (ID 120387498), index "Ref90159CCC" (ID 2), 
because it resides on filegroup "CCC_APPLICATION_new" (ID 8), 
which was not checked.

以下文章描述了類似的情況,並展示了作者如何發現罪魁禍首並解決了這種情況。

參考: SQL Server:切換分區和元數據不一致問題(部落格dbi-services.com)


查找與過時文件組相關的對象

我裝配了這個腳本來檢查表/索引/分區/等的盡可能多的隱藏位置。這可能仍與刪除的文件組文件有關:

請替換DEFAULTRO為您過時的文件組的名稱(例如CCC_APPLICATION

/* ==================================================================
 Author......: hot2use
 Date........: 16.02.2018
 Version.....: 0.1
 Server......: LOCALHOST (first created for)
 Database....: StackExchange
 Owner.......: -
 Table.......: -
 Type........: Script
 Name........: ADMIN_Filegroup_Statement_All_Objects.sql
 Description.: Checks all objects related to filegroups based on the 
 ............  relationship between the data_space_id ID.
 ............      
 History.....:  0.1    h2u First created
 ............      
 ............      
================================================================== */
DECLARE @nvObsoleteFG AS NVARCHAR(50)
SET @nvObsoleteFG = N'DEFAULTRO'

SELECT -- DISTINCT use in conjunction with sys.allocation_units table and objects
      '-->'                            AS DataSpaceNfo
     ,ds.name                          AS DataSpaceName
     ,ds.data_space_id                 AS DatSpacID_DataSpace
     ,'-->'                            AS FileGroupNfo
     ,f.name                           AS FileGrpName
     ,f.data_space_id                  AS DatSpacID_FileGrp
     ,f.[type]                         AS FileGrpType
     ,'-->'                            AS DataBaseFilesNfo
     ,df.data_space_id                 AS DatSpacID_DBFiles
     ,df.[type]                        AS DBFilesType
     ,df.name                          AS DBFilesName
     ,'-->'                            AS ObjectNfo
     ,o.[object_id]                    AS OjbID
     ,o.name                           AS ObjName4HeapsClusters
     ,o.type_desc                      AS ObjTypeDesc
     ,'-->'                            AS IndexNfo
     ,i.name                           AS ObjName4Indexes
     ,i.type_desc                      AS IndTypeDesc
     ,i.[object_id]                    AS IndObjID
     ,i.index_id                       AS IndIndID
     ,'-->'                            AS PartSchemaNfo
     ,ps.name                          AS PartSchemaName
     ,ps.data_space_id                 AS DatSpacID_PartSchema
      -- ,au.type_desc                     AS AllocUnitTypeDesc
      -- ,au.data_space_id                 AS DatSpacID_AllocUnit
FROM   sys.data_spaces                  AS ds
      FULL JOIN sys.filegroups         AS f
           ON  ds.data_space_id = f.data_space_id
      FULL JOIN sys.database_files     AS df
           ON  f.data_space_id = df.data_space_id
      FULL JOIN sys.indexes            AS i
           ON  f.data_space_id = i.data_space_id
      FULL JOIN sys.partition_schemes  AS ps
           ON  f.data_space_id = ps.data_space_id
      FULL JOIN sys.objects            AS o
           ON  i.[object_id] = o.[object_id]         
      -- FULL JOIN sys.allocation_units   AS au
      --      ON  au.data_space_id = f.data_space_id

-- If you omit the whole WHERE clause you get an overview of everything (incl. MS objects)
WHERE  o.is_ms_shipped = 0
      -- if you omit the lower AND you'll get all items related to all filegroups
      AND (
              df.data_space_id=(
                  SELECT data_space_id
                  FROM   sys.filegroups
                  WHERE  NAME = @nvObsoleteFG
              )
              OR f.data_space_id=(
                     SELECT data_space_id
                     FROM   sys.filegroups
                     WHERE  NAME = @nvObsoleteFG
                 ) 
              OR df.data_space_id=(
                     SELECT data_space_id
                     FROM   sys.filegroups
                     WHERE  NAME = @nvObsoleteFG
                 )
              OR ps.data_space_id=(
                     SELECT data_space_id
                     FROM   sys.filegroups
                     WHERE  NAME = @nvObsoleteFG
                 )
          )

***參考:***我的個人劇本

執行它並查看是否顯示包含過時文件組的任何對象。使用data_space_id而不是使用名稱。連接是有意FULL擷取任何“孤立”引用。

或者使用這個較小的腳本來快速檢查過時文件組中的項目:

SELECT o.[name]
     ,o.[type]
     ,i.[name]
     ,i.[index_id]
     ,f.[name]
FROM   sys.indexes i
      INNER JOIN sys.filegroups f
           ON  i.data_space_id = f.data_space_id
      INNER JOIN sys.all_objects o
           ON  i.[object_id] = o.[object_id]
WHERE  i.data_space_id = f.data_space_id
      AND o.type = 'U' -- User Created Tables

參考: SQL SERVER – 列出在數據庫中所有文件組上創建的所有對象(SQLAuthority.com)

引用自:https://dba.stackexchange.com/questions/196719