2011-12-09 45 views
5

El problema aquí está relacionado con otra pregunta que tuve ...¿Cómo puede encontrar huecos de identificación en un conjunto de registros MySQL?

Tengo millones de registros, y el ID de cada uno de esos registros se incrementa automáticamente, desafortunadamente a veces el ID que se genera a veces se descarta por lo hay muchas brechas entre los ID.

Quiero encontrar las lagunas, y volver a utilizar los identificadores que fueron abandonados.

¿Cuál es una forma eficiente de hacer esto en MySQL?

+0

relacionados: http://stackoverflow.com/questions/3718229/stop-mysql-reusing-auto-increment-ids –

+2

Si está utilizando un INT para su clave primaria, que puede tener como 2 mil millones + registros. ¿Por qué molestarse en tratar de llenar los vacíos? ¿Te estás quedando sin números? Encuentro que hay una ventaja al saber que los números corresponden al orden en que se agregaron los registros. – minboost

+1

Tal vez se encontrará con menos problemas de rendimiento al cambiar el tipo de clave principal para BIGINT (si es 4 mil millones de valores proporcionados por int es demasiado corta) de tratar de volver a utilizar los identificadores en un muy gran mesa. –

Respuesta

17

En primer lugar, ¿qué ventaja está tratando de obtener mediante la reutilización de los valores omitidos? Un ordinario INT UNSIGNED le permitirá contar hasta 4.294.967.295. Con "millones de registros", su base de datos tendría que crecer miles de veces antes de quedarse sin identificaciones válidas. (Y a continuación, utilizando un BIGINT UNSIGNED topará que hasta 18,446,744,073,709,551,615 valores.)

Tratando de reciclar los valores de MySQL ha saltado es probable que utilizar una gran cantidad de su tiempo tratando de compensar algo que realmente no molesta en el MySQL primer lugar.

Dicho esto, se pueden encontrar los ID de falta con algo como:

SELECT id + 1 
FROM the_table 
WHERE NOT EXISTS (SELECT 1 FROM the_table t2 WHERE t2.id = the_table.id + 1); 

Esto encontrará sólo el primera número que falta en cada secuencia (por ejemplo, si usted tiene {1, 2, 3, 8, 10} encontrará {4,9}), pero es probable que sea eficiente y, por supuesto, una vez que haya ingresado una identificación, siempre podrá ejecutarla nuevamente.

+1

+1 para una respuesta completa y cuidadosa – qodeninja

+0

si 1 es la primera brecha, no se devolverá – morandi3

+0

En mi caso, cada número que falta es importante, igual que el último párrafo de la respuesta :) +1 Votación hacia arriba – AamirR

2

El siguiente devolverá una fila por cada hueco en el campo entero "n" en mytab:

/* cs will contain 1 row for each contiguous sequence of integers in mytab.n 
    and will have the start of that chain. 
    ce will contain the end of that chain */ 
create temporary table cs (row int auto_increment primary key, n int); 
create temporary table ce like cs; 
insert into cs (n) select n from mytab where n-1 not in (select n from mytab) order by n; 
insert into ce (n) select n from mytab where n+1 not in (select n from mytab) order by n; 
select ce.n + 1 as bgap, cs.n - 1 as egap 
    from cs, ce where cs.row = ce.row + 1; 

Si en lugar de los huecos desea que las cadenas contiguas a continuación, el selecto final debe ser:

select cs.n as bchain, ce.n as echain from cs,ce where cs.row=ce.row; 
+0

la segunda consulta '' seleccionar cs.n como bchain, ce.n como echain de cs, ce donde cs.row = ce.row; '' la unión muestra una brecha más grande que realmente existe pero la primera funciona bien. – magdmartin

1

Esta solución es mejor, en caso de tener que incluir el primer elemento como 1:

SELECT 
    1 AS gap_start, 
    MIN(e.id) - 1 AS gap_end 
FROM 
    factura_entrada e 
WHERE 
    NOT EXISTS(
     SELECT 
      1 
     FROM 
      factura_entrada 
     WHERE 
      id = 1 
    ) 
LIMIT 1 
UNION 
    SELECT 
     a.id + 1 AS gap_start, 
     MIN(b.id)- 1 AS gap_end 
    FROM 
     factura_entrada AS a, 
     factura_entrada AS b 
    WHERE 
     a.id < b.id 
    GROUP BY 
     a.id 
    HAVING 
     gap_start < MIN(b.id); 
Cuestiones relacionadas