5

Il mio database sta invecchiando e una delle mie più grandi colonne INT IDENTITY ha un valore di circa 1,3 miliardi. Questo supererà circa 2,1 miliardi. Ho intenzione di aumentare le dimensioni, ma non voglio farlo troppo presto a causa del numero di record nel database. Potrei sostituire l'hardware del mio database prima che aumenti la dimensione della colonna, il che potrebbe compensare eventuali problemi di prestazioni che ciò potrebbe causare. Voglio anche tenere d'occhio tutte le altre colonne nei miei database che sono piene del 50%. Sono molti tavoli e controllarli manualmente non è pratico.Come faccio a trovare facilmente le colonne IDENTITY in pericolo di overflow?

Ecco come sto ottenendo il valore di ora (io conosco il valore restituito può essere leggermente fuori moda, ma è abbastanza buono per i miei scopi):

PRINT IDENT_CURRENT('MyDatabase.dbo.MyTable') 

Posso usare il INFORMATION_SCHEMA per ottenere questo informazione?

+11

[qui] (http://meta.stackexchange.com/questions/17463/can-i-answer-my-own-questions-even-those-where-i-knew-the-answer- prima-chiedendo) e [qui] (http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/) è il perché. Secondo le FAQ SO, questo comportamento non è solo accettabile, ma è incoraggiato. Continuerò a farlo fino a quando non sarà considerato una cattiva etichetta dalla comunità SO. –

+0

Questa non è una risposta, ma hai iniziato le tue identità da 0 o 1? Se sì, allora invece di aumentare la dimensione della colonna, hai considerato di reimpostare l'identità al più piccolo int? Ciò ti darebbe altri 2 miliardi della stessa dimensione di colonna. –

+0

@AlexKuznetsov: Sì, l'ho preso in considerazione. Potrei usare valori negativi nei progetti futuri, ma c'è così tanto codice scritto per questo database che non voglio rischiare di romperlo. –

risposta

11

È possibile consultare il catalogo di sistema sys.identity_columns vista:

SELECT  
    name, 
    seed_value, increment_value, last_value 
FROM sys.identity_columns 

Questo ti dà il nome, di semi, di incremento e l'ultimo valore per ogni colonna. La vista contiene anche il tipo di dati, quindi puoi facilmente capire quali colonne di identità potrebbero esaurire i numeri in modo immediato ...

+0

Si noti che per le visualizzazioni del database incrociato, last_value potrebbe essere erroneamente riportato come null. IDENT_CURRENT (nome_oggetto (id_oggetto)) restituirà l'ultimo_valore corretto. – jmoreno

5

Ho creato una procedura memorizzata per risolvere questo problema. Utilizza INFORMATION_SCHEMA per trovare le colonne IDENTITY e quindi utilizza IDENT_CURRENT e DATA_TYPE della colonna per calcolare la percentuale piena. Specificare il database come primo parametro, quindi facoltativamente la percentuale minima e il tipo di dati.

EXEC master.dbo.CheckIdentityColumns 'MyDatabase' --all 

EXEC master.dbo.CheckIdentityColumns 'MyDatabase', 50 --columns 50% full or greater 

EXEC master.dbo.CheckIdentityColumns 'MyDatabase', 50, 'int' --only int columns 

uscita Esempio:

Table      Column    Type Percent Full Remaining 
------------------------- ------------------ ------- ------------ --------------- 
MyDatabase.dbo.Table1  Table1ID   int  9   1,937,868,393 
MyDatabase.dbo.Table2  Table2ID   int  5   2,019,944,894 
MyDatabase.dbo.Table3  Table3ID   int  9   1,943,793,775 

Ho creato un promemoria per controllare tutte le mie basi di dati, una volta al mese, e posso registrarmi queste informazioni in un foglio di calcolo.

IDENTITY tracking spreadsheet

CheckIdentityColumns Procedura

USE master 
GO 

CREATE PROCEDURE dbo.CheckIdentityColumns 
    (
    @Database  AS NVARCHAR(128), 
    @PercentFull AS TINYINT   = 0, 
    @Type   AS VARCHAR(8)  = NULL 
    ) 

AS 

--this procedure assumes you are not using negative numbers in your identity columns 

DECLARE @Sql NVARCHAR(3000) 

SET @Sql = 
'USE ' + @Database + ' 

SELECT       
    [Column].TABLE_CATALOG + ''.'' + 
    [Column].TABLE_SCHEMA + ''.'' + 
    [Table].TABLE_NAME   AS [Table], 
    [Column].COLUMN_NAME      AS [Column], 
    [Column].DATA_TYPE    AS [Type], 
    CAST((
    CASE LOWER([Column].DATA_TYPE) 
    WHEN ''tinyint'' 
    THEN (IDENT_CURRENT([Table].TABLE_NAME)/255) 
    WHEN ''smallint'' 
    THEN (IDENT_CURRENT([Table].TABLE_NAME)/32767) 
    WHEN ''int'' 
    THEN (IDENT_CURRENT([Table].TABLE_NAME)/2147483647) 
    WHEN ''bigint'' 
    THEN (IDENT_CURRENT([Table].TABLE_NAME)/9223372036854775807) 
    WHEN ''decimal'' 
    THEN (IDENT_CURRENT([Table].TABLE_NAME)/(([Column].NUMERIC_PRECISION * 10) - 1)) 
    END * 100) AS INT)     AS [Percent Full], 
    REPLACE(CONVERT(VARCHAR(19), CAST(
    CASE LOWER([Column].DATA_TYPE) 
    WHEN ''tinyint'' 
    THEN (255 - IDENT_CURRENT([Table].TABLE_NAME)) 
    WHEN ''smallint'' 
    THEN (32767 - IDENT_CURRENT([Table].TABLE_NAME)) 
    WHEN ''int'' 
    THEN (2147483647 - IDENT_CURRENT([Table].TABLE_NAME)) 
    WHEN ''bigint'' 
    THEN (9223372036854775807 - IDENT_CURRENT([Table].TABLE_NAME)) 
    WHEN ''decimal'' 
    THEN ((([Column].NUMERIC_PRECISION * 10) - 1) - IDENT_CURRENT([Table].TABLE_NAME)) 
    END 
    AS MONEY) , 1), ''.00'', '''')    AS Remaining 


FROM      
    INFORMATION_SCHEMA.COLUMNS     AS [Column] 

    INNER JOIN  
    INFORMATION_SCHEMA.TABLES     AS [Table] 
    ON  [Table].TABLE_NAME     = [Column].TABLE_NAME 

WHERE 
    COLUMNPROPERTY(
     OBJECT_ID([Column].TABLE_NAME), 
     [Column].COLUMN_NAME, ''IsIdentity'') = 1 --true 
    AND [Table].TABLE_TYPE      = ''Base Table'' 
    AND [Table].TABLE_NAME      NOT LIKE ''dt%'' 
    AND [Table].TABLE_NAME      NOT LIKE ''MS%'' 
    AND [Table].TABLE_NAME      NOT LIKE ''syncobj_%'' 
    AND CAST(
    (
    CASE LOWER([Column].DATA_TYPE) 
    WHEN ''tinyint'' 
    THEN (IDENT_CURRENT([Table].TABLE_NAME)/255) 
    WHEN ''smallint'' 
    THEN (IDENT_CURRENT([Table].TABLE_NAME)/32767) 
    WHEN ''int'' 
    THEN (IDENT_CURRENT([Table].TABLE_NAME)/2147483647) 
    WHEN ''bigint'' 
    THEN (IDENT_CURRENT([Table].TABLE_NAME)/9223372036854775807) 
    WHEN ''decimal'' 
    THEN (IDENT_CURRENT([Table].TABLE_NAME)/(([Column].NUMERIC_PRECISION * 10) - 1)) 
    END * 100 
    ) AS INT)         >= ' + CAST(@PercentFull AS VARCHAR(4)) 

IF (@Type IS NOT NULL) 
    SET @Sql = @Sql + 'AND LOWER([Column].DATA_TYPE) = ''' + LOWER(@Type) + '''' 

SET @Sql = @Sql + ' 

ORDER BY 
    [Column].TABLE_CATALOG + ''.'' + 
    [Column].TABLE_SCHEMA + ''.'' + 
    [Table].TABLE_NAME, 
    [Column].COLUMN_NAME' 

EXECUTE sp_executesql @Sql 
GO 
2

Keith Walton ha una query molto completa che è molto buona. Ecco un piccolo più semplice che si basa sul presupposto che le colonne di identità sono tutti interi:

SELECT sys.tables.name AS [Table Name], 
    last_value AS [Last Value],  
    MAX_LENGTH, 
    CAST(cast(last_value as int)/2147483647.0 * 100.0 AS DECIMAL(5,2)) 
     AS [Percentage of ID's Used], 
    2147483647 - cast(last_value as int) AS Remaining 
FROM sys.identity_columns 
    INNER JOIN sys.tables 
     ON sys.identity_columns.object_id = sys.tables.object_id 
ORDER BY last_value DESC 

I risultati sarà simile a questa:

Table Name  Last Value  MAX_LENGTH Percentage of ID's Used Remaining 
My_Table  49181800    4    2.29    2098301847 

Checking Integer Identity Columns

0

Mentre lavorazione a solution per questo problema, abbiamo trovato questo thread sia informativo che interessante (abbiamo anche scritto un dettagliato post about this e descritto come funziona il nostro strumento).

Nella nostra soluzione stiamo interrogando il information_schema per acquisire un elenco di tutte le colonne. Quindi abbiamo scritto un programma che passerebbe attraverso ciascuno di essi e calcolerebbe il massimo e il minimo (contiamo sia per overflow che per underflow).

SELECT 
    b.COLUMN_NAME, 
    b.COLUMN_TYPE, 
    b.DATA_TYPE, 
    b.signed, 
    a.TABLE_NAME, 
    a.TABLE_SCHEMA 
FROM (
    -- get all tables 
    SELECT 
    TABLE_NAME, TABLE_SCHEMA 
    FROM information_schema.tables 
    WHERE 
    TABLE_TYPE IN ('BASE TABLE', 'VIEW') AND 
    TABLE_SCHEMA NOT IN ('mysql', 'performance_schema') 
) a 
JOIN (
    -- get information about columns types 
    SELECT 
    TABLE_NAME, 
    COLUMN_NAME, 
    COLUMN_TYPE, 
    TABLE_SCHEMA, 
    DATA_TYPE, 
    (!(LOWER(COLUMN_TYPE) REGEXP '.*unsigned.*')) AS signed 
    FROM information_schema.columns 
) b ON a.TABLE_NAME = b.TABLE_NAME AND a.TABLE_SCHEMA = b.TABLE_SCHEMA 
ORDER BY a.TABLE_SCHEMA DESC; 
Problemi correlati