5

Mi base de datos está envejeciendo, y una de mis mayores columnas INT IDENTITY tiene un valor de alrededor de 1.300 millones. Esto se desbordará alrededor de 2.1 billones. Planeo aumentar su tamaño, pero no quiero hacerlo demasiado pronto debido a la cantidad de registros en la base de datos. Puedo reemplazar el hardware de mi base de datos antes de aumentar el tamaño de la columna, lo que podría compensar cualquier problema de rendimiento que esto pueda causar. También quiero vigilar todas las otras columnas en mis bases de datos que están más del 50% llenas. Son muchas tablas y comprobarlas manualmente no es práctico.¿Cómo puedo encontrar fácilmente las columnas de IDENTIDAD en peligro de desbordamiento?

Esta es la forma en que estoy recibiendo el valor ahora (sé que el valor devuelto puede ser un poco fuera de fecha, pero es lo suficientemente bueno para mis propósitos):

PRINT IDENT_CURRENT('MyDatabase.dbo.MyTable') 

¿Puedo utilizar el INFORMATION_SCHEMA para conseguir este ¿información?

+11

[aquí] (http://meta.stackexchange.com/questions/17463/can-i-answer-my-own-questions-even-those-where-i-knew-the-answer- antes de preguntar) y [aquí] (http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/) es por qué. Según las preguntas frecuentes de SO, este comportamiento no solo es aceptable, sino que se fomenta. Continuaré haciéndolo hasta que la comunidad de SO lo considere una mala etiqueta. –

+0

Esta no es una respuesta, pero ¿ha comenzado sus identidades desde 0 o 1? En caso afirmativo, en lugar de aumentar el tamaño de la columna, ¿ha considerado restablecer la identidad a la int más pequeña? Eso le daría 2 mil millones adicionales del mismo tamaño de columna. –

+0

@AlexKuznetsov: Sí, lo he considerado. Puedo usar valores negativos en proyectos futuros, pero hay tanto código escrito para esta base de datos que no quiero arriesgarme a romperlo. –

Respuesta

11

Puede consultar el sys.identity_columns sistema vista de catálogo:

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

Esto le da el nombre, la semilla, incremento y último valor para cada columna. La vista también contiene el tipo de datos, por lo que puede averiguar fácilmente qué columnas de identidad se están quedando sin números pronto ...

+0

Tenga en cuenta que para vistas de bases de datos cruzadas, last_value puede informarse incorrectamente como nulo. IDENT_CURRENT (object_name (object_id)) devolverá el last_value correcto. – jmoreno

5

Creé un procedimiento almacenado para resolver este problema. Utiliza el INFORMATION_SCHEMA para buscar las columnas IDENTITY y luego usa IDENT_CURRENT y DATA_TYPE de la columna para calcular el porcentaje completo. Especifique la base de datos como el primer parámetro y luego, opcionalmente, el porcentaje mínimo y el tipo de datos.

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 

Ejemplo de salida:

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 

que creó un recordatorio para revisar todos mis bases de datos una vez al mes, y los recopila en una hoja de cálculo.

IDENTITY tracking spreadsheet

CheckIdentityColumns Procedimiento

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 tiene una consulta muy completa que es muy buena. He aquí un pequeño simple que se basa en la suposición de que las columnas de identidad son todos los números enteros:

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 

Los resultados se verá así:

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

Checking Integer Identity Columns

0

mientras que la elaboración a solution para este problema, encontramos este hilo informativo e interesante (también escribimos un detallado post about this y describimos cómo funciona nuestra herramienta).

En nuestra solución estamos consultando el information_schema para adquirir una lista de todas las columnas . Luego escribimos un programa que pasaría por cada uno de ellos y calcularía el máximo y el mínimo (contabilizamos tanto el desbordamiento como el desbordamiento).

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; 
Cuestiones relacionadas