Impossibile rimuovere il filegroup senza file associati


8

Riscontro alcuni strani messaggi di errore su SQL Server 2017 CU3. Sto migrando database e riorganizzando filegroup. "Riorganizzando" intendo che utilizzo una procedura memorizzata che crea una funzione di partizione e uno schema di partizione sul nuovo filegroup per un oggetto, ricostruisce gli indici durante il partizionamento e quindi rimuove il partizionamento.

Alla fine ho alcuni filegroup vuoti. I loro file vengono rimossi . Anche il filegroup stesso viene rimosso. Questo funziona bene nella maggior parte dei casi. Tuttavia per due database ho rimosso i file ... mi è rimasto un filegroup con nessun file associato ma

ALTER DATABASE REMOVE FILEGROUP

genera un errore 5042:

Il filegroup 'xyz' non può essere rimosso perché non è vuoto.

Domanda

Come posso liberarmi di quel filegroup vuoto ... quale potrebbe essere il problema?

Ho già letto alcuni problemi comuni, tuttavia non sono presenti nel mio sistema:

  • controllato:

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

    0 righe ... nessun oggetto di partizionamento lasciato nel database

  • UPDATE STATISTICS per tutti gli oggetti nel database

    nessun effetto

  • Verifica gli indici nel filegroup:

    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 righe

  • Verifica la presenza di oggetti nel filegroup:

    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 righe

Ho anche provato DBCC SHRINKFILEcon il parametro EMPTYFILEprima di rimuovere il file dal filegroup. Non ha molto senso per me, tuttavia ho letto le soluzioni per descriverlo come una soluzione. Non ha avuto alcun effetto comunque.


Ho avuto qualche speranza leggendo questa domanda per errore del server e ho provato quanto segue:

  • Aggiorna tutte le statistiche
  • Elimina tutte le statistiche che non sono correlate agli indici

Tuttavia questo non ha avuto effetto. Ho ancora un filegroup senza file associato e il filegroup non può essere eliminato. Sono totalmente perplesso perché ciò accade in alcuni database e non in altri (con la stessa struttura). Quando eseguo DBCC CHECK FILEGROUPquesto filegroup vuoto, ricevo un sacco di messaggi di errore come il seguente:

Impossibile elaborare l'ID set di righe 72057594712162304 dell'oggetto "STORY_TRANSLATIONSCCC" (ID 120387498), indice "Ref90159CCC" (ID 2), poiché risiede sul filegroup "CCC_APPLICATION_new" (ID 8), che non è stato verificato.

Risultati DBCC per "STORY_TRANSLATIONSCCC". Esistono 0 righe in 0 pagine per l'oggetto "STORY_TRANSLATIONSCCC".

È normale o indica qualcosa di insolito?

Questa domanda potrebbe essere un duplicato, tuttavia non riesco a trovare una soluzione funzionante per me in altre domande su dba.stackexchange. Dai un'occhiata all'elenco di ciò che ho già provato. Ciò è identico alle soluzioni descritte in Impossibile rimuovere i filegroup inutilizzati .

Più dettagli

Forse aiuta a capire cosa faccio prima che si verifichi l'errore. Sto pianificando una migrazione a un nuovo server. Attualmente sto testando questo su un'istanza di prova. I database vengono ripristinati dal server prod e il modello di recupero è passato a semplice. Il mio obiettivo è di ristrutturare i filegroup e passare da un modello con un file per filegroup a un modello con due file per gruppo di file. A tal fine, creo nuovi filegroup vuoti con due file ciascuno e sposto i dati. Sfortunatamente la maggior parte degli oggetti ha dati LOB (XML e binari) ... quindi utilizzo il partizionamento come aiuto per spostare anche i dati lob. Alla fine tutti i dati risiedono nei nuovi filegroup e i vecchi filegroup sono vuoti. Quindi rimuovo tutti i file e rimuovo anche il rispettivo filegroup. Il filegroup primario rimane e viene semplicemente aggiunto un altro file.una mia domanda . Questo processo funziona bene ma in due database i file possono essere eliminati ma il filegroup no. Sorprendentemente la struttura di questi database dovrebbe essere la stessa della struttura di altri database in cui non si sono verificati problemi nel processo di spostamento dei dati e rimozione dei vecchi filegroup.

Quindi ecco un elenco di filegroup e file dei due database in cui si verifica il problema:

  1. CCC_GENTE

prima

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

dopo

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

Spero che sia di aiuto. C'è anche un secondo database in cui i nomi dei filegroup sono diversi ma lo lascio per brevità.


1
So che non menziona SQL2017 ma mi chiedo se il bug è ancora lì nel 2017? support.microsoft.com/en-us/help/3132058/…
SqlWorldWide

@SqlWorldWide: grazie per il link. Tuttavia non ho indici full-text e ho rimosso personalmente le funzioni e gli schemi di partizione ... quindi immagino che quel link non si applichi al mio problema.
Martin Guth,

Riesci a stampare l' intero errore 5042, lo stato indica qual è il problema.
Sean Gallardy - Utente ritirato il

@ SeanGallardy-Microsoft: messaggio 5042, livello 16, stato 8, riga 1 Impossibile rimuovere il filegroup 'FG_AUDIT' perché non è vuoto.
Martin Guth,

Grazie :) Lo stato 8 indica che il filegroup è utilizzato da un oggetto. Questo è diverso dall'articolo di supporto (questo è lo stato 12 che significa che fg è usato da uno schema di partizione). La cosa strana è che hai detto che il filegroup non contiene file. Presumo che siano stati eseguiti più backup del log (se in pieno / in blocco) da quando si è verificato il problema?
Sean Gallardy - Utente ritirato

Risposte:


4

Doppio controllo dei filegroup nel database

Verificare che il filegroup non contenga alcun file lasciato emettendo il comando seguente:

use [DB]
go
sp_helpfilegroup 

Questo produrrà un elenco di filegroup:

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

... e quindi per ogni filegroup elencato eseguire

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

L'output potrebbe essere simile al seguente:

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

.... e il secondo output potrebbe essere:

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

Eliminazione del filegroup

Se hai ancora un file associato a uno dei tuoi filegroup, il comando completo per eliminare il file logico del filegroup e il filegroup stesso sarebbe:

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

Il filegroup 'xyz' è predefinito

Se viene visualizzato un messaggio di errore quando si tenta di rimuovere il file logico del filegroup simile al seguente:

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.

... quindi dovrai impostare il PRIMARYfilegroup come DEFAULTfilegroup:

ALTER DATABASE [DB] MODIFY FILEGROUP [PRIMARY] DEFAULT

Il filegroup 'xyz' è ReadOnly

Tuttavia, se il messaggio di errore è il seguente:

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

... quindi dovrai rimuovere la proprietà READ_ONLY sul xyzfilegroup:

ALTER DATABASE [DB] MODIFY FILEGROUP [xyz] READWRITE

Ora dovresti essere in grado di eliminare il file logico del filegroup e il filegroup stesso.

Transazioni aperte

Se in realtà non si dispone di un file (nome_logico / nome_file_file) associato al filegroup che xyzsi sta tentando di eliminare, l'esecuzione di un backup del registro delle transazioni potrebbe rilasciare eventuali transazioni che ostacolano l'ulteriore eliminazione del filegroup.

Componi il 911

Se tutto il resto fallisce, potresti prendere in considerazione l'apertura di una chiamata con Microsoft.


Mancata corrispondenza dei metadati

Aggiunto dopo ulteriori ricerche

Apparentemente ci sono casi in cui i metadati nel database non riflettono la posizione effettiva degli oggetti.

Riferimento:
- FIX: errore di incoerenza dei metadati dopo il passaggio da una partizione di tabella all'altra e l' eliminazione di file e filegroup corrispondenti (supporto Microsoft)
- FIX: errore si verifica quando si tenta di eliminare o eliminare filegroup o schemi di partizione e funzioni in SQL Server (supporto Microsoft)

Questi due casi sembrano essere stati risolti rispettivamente con Cumulative Update 3 per SQL Server 2014 SP1 e Cumulative Update 1 per SQL Server 2016 . Non si applicano alla tua situazione, ma mostrano che a volte i metadati possono essere sbagliati.

L'elemento che sembra bloccare l'eliminazione del filegroup è l'indice, che potrebbe essere memorizzato con metadati errati.

Possibile soluzione

Valuta di ricostruire l'indice a Ref90159CCCcui fa riferimento il messaggio di errore.

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.

Il seguente articolo descrive una situazione simile e mostra come l'autore ha rilevato il colpevole e risolto la situazione.

Riferimento: SQL Server: switch incoerenza partizione e metadati (Blog dbi-services.com)


Trova oggetti relativi al filegroup obsoleto

Ho preparato questo script per controllare il maggior numero possibile di nascondigli per tabelle / indici / partizioni / ecc. che potrebbe essere ancora relativo al file filegroup rilasciato:

Sostituisci DEFAULTROcon il nome del tuo filegroup obsoleto (ad es. 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
                  )
           )

Riferimento: la mia sceneggiatura personale

Eseguilo e controlla se vengono visualizzati oggetti contenenti il ​​tuo filegroup obsoleto. Vai con il data_space_idpiuttosto che con il nome. I join sono intenzionalmente FULLcatturati da riferimenti "orfani".

In alternativa, utilizza questo script più piccolo per controllare rapidamente gli elementi nel filegroup 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

Riferimento: SERVER SQL - Elenca tutti gli oggetti creati in tutti i filegroup nel database (SQLAuthority.com)


sp_helpfilegroup: FG_AUDIT groupid 2 filecount 0 nessun file
Martin Guth

il database è in un semplice modello di recupero e al momento non ci sono transazioni aperte (sul testing server nel suo insieme)
Martin Guth

Grazie per il feedback. Potresti aggiungere queste informazioni alla tua domanda? Darò il tuo messaggio di errore ( ...CCC_APPLICATION_new...; quello è il filegroup temporaneo?) Qualche altro pensiero e cerco di riprodurlo nel mio ambiente.
John aka hot2use,

1
CCC_APPLICATION_new non è il filegroup temporaneo ... è il filegroup in cui il contenuto è stato spostato ... dovrebbe essere rinominato in "CCC_APPLICATION" ... tuttavia funziona solo se il filegroup senza file associato denominato CCC_APPLICATION è stato eliminato o ribattezzato (ma non voglio averlo in giro)
Martin Guth,

1
per chiarimenti: ho riscontrato il problema in due diversi database ... uno con il vecchio filegroup CCC_APPLICATION e il nuovo filegroup CCC_APPLICATION_new e uno con il vecchio filegroup FG_AUDIT e il nuovo filegroup CCC_AUDIT
Martin Guth

2

Dopo quattro mesi, il supporto Microsoft ha trovato una soluzione. C'era davvero una tabella che si riferiva a questo filegroup presumibilmente vuoto.

La tabella è stata identificata dalla seguente dichiarazione:

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'

Dopo aver spostato i dati su una nuova tabella e aver eliminato la tabella problematica, il filegroup è stato rimosso con successo. Il processo di spostamento dei dati è stato: creare una nuova tabella con la stessa struttura e gli stessi indici, copiare i dati tramite SELECT INTO, eliminare la vecchia tabella, rinominare la nuova tabella (e ovviamente occuparsi delle chiavi esterne se ce ne sono in tutto il processo) )


Stavo cercando questa risposta da anni. Molte grazie!
Christian4145,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.