Mar*_*uth 9 sql-server filegroups sql-server-2017
我在 SQL Server 2017 CU3 上遇到一些奇怪的错误消息。我正在迁移数据库并重新组织文件组。“重组”是指我使用存储过程在新文件组上为对象创建分区函数和分区方案,在分区时重建索引,然后删除分区。
最后我有一些空的文件组。他们的文件被删除。文件组本身也被删除。这在大多数情况下效果很好。但是,对于两个数据库,我删除了文件...留下了一个没有关联文件的文件组,但是
ALTER DATABASE REMOVE FILEGROUP
Run Code Online (Sandbox Code Playgroud)
抛出错误 5042:
无法删除文件组“xyz”,因为它不为空。
我怎样才能摆脱那个空的文件组......可能是什么问题?
我已经阅读了一些常见问题,但是它们在我的系统中不存在:
检查:
SELECT * FROM sys.partition_schemes;
SELECT * FROM sys.partition_functions;
Run Code Online (Sandbox Code Playgroud)
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'
Run Code Online (Sandbox Code Playgroud)
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'
Run Code Online (Sandbox Code Playgroud)
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 的其他问题中找不到适合我的解决方法。请看一下我已经尝试过的列表。这与无法删除未使用的文件组中描述的解决方案相同。
更多细节
也许有助于理解我在错误发生之前所做的事情。我正计划迁移到新服务器。我目前正在测试实例上对此进行测试。数据库从生产服务器恢复,恢复模式切换到简单。我的目标是重组文件组,并从每个文件组一个文件的模型移动到每个文件组两个文件的模型。为了实现这一点,我创建了新的空文件组,每个文件组有两个文件,然后移动数据。不幸的是,大多数对象都有 LOB 数据(XML 和二进制)……所以我也利用分区作为移动 lob 数据的助手。最后,所有数据都驻留在新文件组中,旧文件组为空。然后我删除所有文件并删除相应的文件组。主文件组仍然存在,只是添加了另一个文件。我的问题。这个过程工作正常,但在两个数据库中文件可以被删除,但文件组不能。令人惊讶的是,这些数据库的结构应该与其他数据库的结构相同,并且在移动数据和删除旧文件组的过程中没有遇到任何问题。
所以这里是出现问题的两个数据库的文件组和文件的列表:
前
+-----------------+------------+
| Filegroup | Filename |
+-----------------+------------+
| CCC_APPLICATION | CCC_APP |
+-----------------+------------+
| CCC_ARCHIVE | CCC_ARCHIV |
+-----------------+------------+
| CCC_AXN | CCC_AXN |
+-----------------+------------+
| CCC_GDV | CCC_GDV |
+-----------------+------------+
| PRIMARY | CCC |
+-----------------+------------+
Run Code Online (Sandbox Code Playgroud)
后
+-----------------+--------------------------+--------------------+----------------------------------------------------+
| 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 |
+-----------------+--------------------------+--------------------+----------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)
我希望这会有所帮助。还有第二个数据库,其中文件组名称不同,但为简洁起见,我将其省略。
通过发出以下命令验证文件组没有任何附加的文件:
use [DB]
go
sp_helpfilegroup
Run Code Online (Sandbox Code Playgroud)
这将产生一个文件组列表:
groupname | groupid | filecount
-----------+---------+-----------
PRIMARY | 1 | 1
xyz | 2 | 1
Run Code Online (Sandbox Code Playgroud)
...然后对列出的每个文件组执行
use [DB]
go
sp_helpfilegroup @filegroupname='PRIMARY'
go
sp_helpfilegroup @filegroupname='xyz'
Run Code Online (Sandbox Code Playgroud)
输出可能如下所示:
groupname | groupid | filecount
-----------+---------+------------
xyz | 2 | 1
Run Code Online (Sandbox Code Playgroud)
....第二个输出可能是:
file_in_group | fileid | filename | size | maxsize | growth
------------------+--------+-----------------------------------+---------+-----------+---------
xyz_logical_name | 3 | X:\SQL\SQL_DATA\xyz_filegroup.ndf | 5120 KB | Unlimited | 1024 KB
Run Code Online (Sandbox Code Playgroud)
如果您仍然有一个与您的文件组之一相关联的文件,那么删除文件组的逻辑文件和文件组本身的完整命令将是:
USE [DB]
GO
ALTER DATABASE [DB] REMOVE FILE [xyz_logical_name]
GO
ALTER DATABASE [DB] REMOVE FILEGROUP [xyz]
GO
Run Code Online (Sandbox Code Playgroud)
如果在尝试删除文件组的逻辑文件时收到错误消息,如下所示:
Run Code Online (Sandbox Code Playgroud)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
Run Code Online (Sandbox Code Playgroud)
但是,如果错误消息如下:
Run Code Online (Sandbox Code Playgroud)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
Run Code Online (Sandbox Code Playgroud)
您现在应该能够删除文件组的逻辑文件和文件组本身。
如果您确实没有与xyz您尝试删除的文件组关联的文件 (logical_name / pyhsical_file_name) ,则执行事务日志备份可能会释放任何阻碍进一步删除文件组的事务。
如果所有其他方法都失败了,您可能需要考虑与 Microsoft 打个电话。
进一步研究后添加
显然,有时数据库中的元数据不能反映对象的实际位置。
参考:
- FIX:切换表分区并删除相应的文件和文件组后出现元数据不一致错误(Microsoft 支持)
- FIX:当您尝试删除或删除 SQL Server 中的文件组或分区方案和函数时发生错误(Microsoft 支持)
这两种情况似乎分别通过SQL Server 2014 SP1 的累积更新 3和SQL Server 2016 的累积更新 1得到解决。它们不适用于您的情况,但它们表明有时元数据可能是错误的。
似乎阻止文件组删除的项目是索引,它可能存储有错误的元数据。
考虑重建Ref90159CCC错误消息中引用的索引。
Run Code Online (Sandbox Code Playgroud)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
)
)
Run Code Online (Sandbox Code Playgroud)
参考:我的个人脚本
运行它并查看是否显示任何包含过时文件组的对象。使用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
Run Code Online (Sandbox Code Playgroud)
参考:SQL SERVER – 列出在数据库中的所有文件组上创建的所有对象(SQLAuthority.com)
四个月后,微软支持人员找到了解决方案。确实有一个表引用了这个可能是空的文件组。
该表由以下语句标识:
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'
Run Code Online (Sandbox Code Playgroud)
将数据移至新表并删除有问题的表后,文件组已成功删除。移动数据的过程是:创建一个具有相同结构和索引的新表,通过 SELECT INTO 复制数据,删除旧表,重命名新表(当然,如果整个过程中有外键,请注意外键) )