No se puede eliminar el grupo de archivos sin archivos asociados

8

Estoy experimentando algunos mensajes de error extraños en SQL Server 2017 CU3. Estoy migrando bases de datos y reorganizando grupos de archivos. Por "reorganizar" quiero decir que uso un procedimiento almacenado que crea una función de partición y un esquema de partición en el nuevo grupo de archivos para un objeto, reconstruye los índices durante la partición y luego elimina la partición.

Al final tengo algunos grupos de archivos vacíos. Sus archivos son eliminados . También se eliminan los propios grupos de archivos. Esto funciona bien en la mayoría de los casos. Sin embargo, para dos bases de datos eliminé los archivos ... me queda un grupo de archivos sin ningún archivo asociado pero

ALTER DATABASE REMOVE FILEGROUP

arroja un error 5042:

El grupo de archivos 'xyz' no se puede eliminar porque no está vacío.

Pregunta

¿Cómo puedo deshacerme de ese grupo de archivos vacío ... cuál podría ser el problema?

Ya he leído algunos problemas comunes, sin embargo, no están presentes en mi sistema:

  • Comprobado:

    SELECT * FROM sys.partition_schemes;
    SELECT * FROM sys.partition_functions;

    0 filas ... no quedan objetos de partición en la base de datos

  • UPDATE STATISTICS para todos los objetos en la base de datos

    sin efecto

  • Comprueba los índices en el grupo de archivos:

    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 filas

  • Comprueba los objetos en el grupo de archivos:

    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 filas

También probé DBCC SHRINKFILEcon el parámetro EMPTYFILEantes de eliminar el archivo del grupo de archivos. Realmente no tiene sentido para mí, sin embargo, leo soluciones para describir eso como una solución. No tuvo efecto de todos modos.


Tengo algo de esperanza al leer esta pregunta sobre la falla del servidor e intenté lo siguiente:

  • Actualizar todas las estadísticas
  • Descarte todas las estadísticas que no estén relacionadas con índices

Sin embargo, esto no tuvo ningún efecto. Todavía tengo un grupo de archivos sin ningún archivo asociado y el grupo de archivos no se puede eliminar. Estoy totalmente perplejo ya que esto sucede en algunas bases de datos y no en otras (con la misma estructura). Cuando realizo DBCC CHECK FILEGROUPen este grupo de archivos vacío recibo un montón de mensajes de error como el siguiente:

No se puede procesar el ID de conjunto de filas 72057594712162304 del objeto "STORY_TRANSLATIONSCCC" (ID 120387498), índice "Ref90159CCC" (ID 2), porque reside en el grupo de archivos "CCC_APPLICATION_new" (ID 8), que no se verificó.

Resultados de DBCC para 'STORY_TRANSLATIONSCCC'. Hay 0 filas en 0 páginas para el objeto "STORY_TRANSLATIONSCCC".

¿Es esto normal o apunta a algo inusual?

Esta pregunta puede ser un duplicado, sin embargo, no puedo encontrar una solución para mí en otras preguntas sobre dba.stackexchange. Echa un vistazo a la lista de lo que ya he probado. Esto es idéntico a las soluciones descritas en No se pueden eliminar los grupos de archivos no utilizados .

Más detalles

Quizás sea útil entender lo que hago antes de que ocurra el error. Estoy planeando una migración a un nuevo servidor. Actualmente estoy probando esto en una instancia de prueba. Las bases de datos se restauran desde el servidor de producción y el modelo de recuperación cambia a simple. Mi objetivo es reestructurar los grupos de archivos y pasar de un modelo con un archivo por grupo de archivos a un modelo con dos archivos por grupo de archivos. Para lograrlo, creo nuevos grupos de archivos vacíos con dos archivos cada uno y muevo los datos. Desafortunadamente, la mayoría de los objetos tienen datos LOB (XML y binario) ... así que aprovecho la partición como ayuda para mover los datos lob también. Al final, todos los datos residen en los nuevos grupos de archivos y los grupos de archivos antiguos están vacíos. Luego elimino todos los archivos y elimino el grupo de archivos correspondiente también. El grupo de archivos primario permanece y solo se agrega otro archivo.pregunta mía . Este proceso funciona bien pero en dos bases de datos los archivos se pueden eliminar pero el grupo de archivos no. Sorprendentemente, la estructura de estas bases de datos debería ser la misma que la estructura de otras bases de datos si no se encuentran problemas en el proceso de mover los datos y eliminar los antiguos grupos de archivos.

Aquí hay una lista de grupos de archivos y archivos de las dos bases de datos donde ocurre el problema:

  1. CCC_GENTE

antes de

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

después

    +-----------------+--------------------------+--------------------+----------------------------------------------------+
| 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                   |
+-----------------+--------------------------+--------------------+----------------------------------------------------+

Espero que ayude un poco. También hay una segunda base de datos donde los nombres de los grupos de archivos son diferentes, pero lo dejo por razones de brevedad.

Martin Guth
fuente
1
Sé que no menciona SQL2017, pero me pregunto si el error todavía está allí en 2017. support.microsoft.com/en-us/help/3132058/…
SqlWorldWide
@SqlWorldWide: Gracias por el enlace. Sin embargo, no tengo ningún índice de texto completo y eliminé las funciones y esquemas de partición ... por lo tanto, supongo que ese enlace no se aplica a mi problema.
Martin Guth
¿Puede imprimir todo el error 5042? El estado indica cuál es el problema.
Sean Gallardy - Usuario retirado
@ SeanGallardy-Microsoft: Mensaje 5042, Nivel 16, Estado 8, Fila 1 El grupo de archivos 'FG_AUDIT' no se puede eliminar porque no está vacío.
Martin Guth
Gracias :) El estado 8 significa que el grupo de archivos está siendo utilizado por un objeto. Esto es diferente al artículo de soporte (ese es el estado 12, lo que significa que el esquema de partición usa el fg). Lo extraño es que dijiste que el grupo de archivos no tiene archivos. ¿Supongo que se han realizado múltiples copias de seguridad de registros (si están completas / masivas) desde que ocurrió el problema?
Sean Gallardy - Usuario retirado

Respuestas:

4

Verificación doble de grupos de archivos en la base de datos

Verifique que el grupo de archivos no tenga ningún archivo adjunto emitiendo el siguiente comando:

use [DB]
go
sp_helpfilegroup 

Esto producirá una lista de grupos de archivos:

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

... y luego para cada grupo de archivos listado ejecutar

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

El resultado podría verse así:

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

.... y la segunda salida podría ser:

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

Eliminar el grupo de archivos

Si aún tiene un archivo asociado con uno de sus grupos de archivos, entonces el comando completo para eliminar el archivo lógico del grupo de archivos y el grupo de archivos en sí sería:

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

El grupo de archivos 'xyz' es el predeterminado

Si recibe un mensaje de error al intentar eliminar el archivo lógico del grupo de archivos que se ve así:

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.

... entonces tendrá que establecer el grupo de PRIMARYarchivos como el grupo de DEFAULTarchivos:

ALTER DATABASE [DB] MODIFY FILEGROUP [PRIMARY] DEFAULT

El grupo de archivos 'xyz' es de solo lectura

Sin embargo, si el mensaje de error es el siguiente:

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

... entonces tendrá que eliminar la propiedad READ_ONLY en el grupo de xyzarchivos:

ALTER DATABASE [DB] MODIFY FILEGROUP [xyz] READWRITE

Ahora debería poder soltar el archivo lógico del grupo de archivos y el propio grupo de archivos.

Transacciones Abiertas

Si realmente no tiene un archivo (nombre_lógico / nombre_archivo_pídico) asociado con el grupo de archivos xyzque está tratando de eliminar, realizar una copia de seguridad del registro de transacciones podría liberar cualquier transacción que dificulte la eliminación del grupo de archivos.

Marca 911

Si todo lo demás falla, es posible que desee considerar abrir una llamada con Microsoft.


Desajuste de metadatos

Agregado después de más investigación

Aparentemente hay casos en que los metadatos en la base de datos no reflejan la ubicación real de los objetos.

Referencia:
- REVISIÓN: error de inconsistencia de metadatos después de cambiar las particiones de la tabla y soltar los archivos y grupos de archivos correspondientes (Soporte de Microsoft)
- REVISIÓN: El error ocurre cuando intenta colocar o eliminar grupos de archivos o esquemas y funciones de partición en SQL Server (Soporte de Microsoft)

Estos dos casos parecen resolverse con la actualización acumulativa 3 para SQL Server 2014 SP1 y la actualización acumulativa 1 para SQL Server 2016, respectivamente. No se aplican a su situación, pero muestran que a veces los metadatos pueden estar equivocados.

El elemento que parece estar bloqueando la eliminación de su grupo de archivos es el índice, que podría almacenarse con metadatos incorrectos.

Solución posible

Considere reconstruir el índice al Ref90159CCCque se hace referencia en el mensaje de error.

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.

El siguiente artículo describe una situación similar y muestra cómo el autor detectó al culpable y resolvió la situación.

Referencia: SQL Server: problema de inconsistencia de metadatos y particiones de conmutador (Blog dbi-services.com)


Buscar objetos relacionados con el grupo de archivos obsoleto

Arreglé este script para verificar la mayor cantidad posible de escondites para tablas / índices / particiones / etc. que aún podría estar relacionado con el archivo de grupo de archivos descartado:

Reemplácelo DEFAULTROcon el nombre de su grupo de archivos obsoleto (p CCC_APPLICATION. Ej. )

 /* ==================================================================
  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
                  )
           )

Referencia: mi guión personal

Ejecútelo y vea si se muestran objetos que contengan su grupo de archivos obsoleto. Ir con el en data_space_idlugar de con el nombre. Las uniones son intencionalmente FULLpara capturar referencias "huérfanas".

Alternativamente, use este script más pequeño para verificar rápidamente los elementos del grupo de archivos obsoleto:

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

Referencia: SERVIDOR SQL - Listar todos los objetos creados en todos los grupos de archivos en la base de datos (SQLAuthority.com)

John aka hot2use
fuente
sp_helpfilegroup: FG_AUDIT groupid 2 filecount 0 no files
Martin Guth
la base de datos está en un modelo de recuperación simple y actualmente no hay transacciones abiertas (en el servidor de prueba en su conjunto)
Martin Guth
Gracias por la respuesta. ¿Podría agregar esta información a su pregunta? Le daré a su mensaje de error (¿ ...CCC_APPLICATION_new...es ese el grupo de archivos temporal?) Algunas ideas más y trataré de reproducirlo en mi entorno.
John aka hot2use
1
CCC_APPLICATION_new no es el grupo de archivos temporal ... es el grupo de archivos al que se han movido los contenidos ... se debe cambiar el nombre a "CCC_APPLICATION" ... sin embargo, esto solo funciona si el grupo de archivos sin ningún archivo asociado llamado CCC_APPLICATION se ha eliminado o renombrado (pero no quiero tenerlo dando vueltas)
Martin Guth
1
para aclarar: Tengo el problema en dos bases de datos diferentes ... uno con el antiguo grupo de archivos CCC_APPLICATION y el nuevo grupo de archivos CCC_APPLICATION_new y otro con el antiguo grupo de archivos FG_AUDIT y el nuevo grupo de archivos CCC_AUDIT
Martin Guth
2

Después de cuatro meses, el soporte técnico de Microsoft encontró una solución. De hecho, había una tabla que se refería a este grupo de archivos presumiblemente vacío.

La tabla fue identificada por la siguiente declaración:

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'

Después de mover los datos a una nueva tabla y soltar la tabla problemática, el grupo de archivos se eliminó con éxito. El proceso de mover los datos fue: crear una nueva tabla con la misma estructura e índices, copiar datos a través de SELECT INTO, soltar la tabla anterior, cambiar el nombre de la nueva tabla (y, por supuesto, cuidar las claves externas si hay alguna en todo el proceso) )

Martin Guth
fuente
Estaba buscando esta respuesta durante años. ¡Muchas gracias!
Christian4145