una todos tabla registros los entre ejemplo diferencia delete borrar sql sql-server-2008 tsql sql-delete truncate

sql - todos - Cómo eliminar filas de manera eficiente sin usar Truncar tabla en una tabla de más de 500,000 filas



truncate table sql server ejemplo (7)

Como supongo, la mejor manera de eliminar una gran cantidad de registros es eliminarlos por Primary Key . (¿Qué es Primary Key ver aquí )

Por lo tanto, debe generar la secuencia de comandos tsql que contiene toda la lista de líneas para eliminar y luego ejecutar esta secuencia de comandos.

Por ejemplo, el siguiente código generará ese archivo

GO SET NOCOUNT ON SELECT ''DELETE FROM DATA_ACTION WHERE ID = '' + CAST(ID AS VARCHAR(50)) + '';'' + CHAR(13) + CHAR(10) + ''GO'' FROM DATA_ACTION WHERE YEAR(AtTime) = 2014

El archivo de salida va a tener registros como

DELETE FROM DATA_ACTION WHERE ID = 123; GO DELETE FROM DATA_ACTION WHERE ID = 124; GO DELETE FROM DATA_ACTION WHERE ID = 125; GO

Y ahora debe usar la utilidad SQLCMD para ejecutar este script.

sqlcmd -S [Instance Name] -E -d [Database] -i [Script]

Puede encontrar este enfoque explicado aquí https://www.mssqltips.com/sqlservertip/3566/deleting-historical-data-from-a-large-highly-concurrent-sql-server-database-table/

Digamos que tenemos Ventas de tabla con 30 columnas y 500,000 filas. Me gustaría eliminar 400,000 en la tabla (aquellos donde "toDelete=''1''" ).

Pero tengo algunas limitaciones:

  • la mesa es leída / escrita "a menudo" y no me gustaría una "eliminación" larga para tomar mucho tiempo y bloquear la mesa por mucho tiempo
  • Necesito saltear el registro de transacciones (como con un TRUNCATE ) pero mientras hago un "DELETE ... WHERE..." (Necesito poner una condición), pero no he encontrado ninguna manera de hacer esto ...

Cualquier consejo sería bienvenido para transformar una

DELETE FROM Sales WHERE toDelete=''1''

a algo más particionado y posiblemente registro de transacciones gratis.


Debería intentar darle una pista ROWLOCK para que no bloquee toda la tabla. Sin embargo, si elimina muchas filas, se producirá una escalada de bloqueo.

Además, asegúrese de tener un índice filtrado no agrupado (solo para 1 valor) en la columna toDelete . Si es posible, conviértalo en una columna de bit, no varchar (o lo que es ahora).

DELETE FROM Sales WITH(ROWLOCK) WHERE toDelete=''1''

En última instancia, puede intentar iterar sobre la tabla y eliminar en fragmentos.

Actualizado

Como los bucles while y las eliminaciones de fragmentos son el nuevo rosa aquí, también incluiré mi versión (combinada con mi respuesta anterior):

SET ROWCOUNT 100 DELETE FROM Sales WITH(ROWLOCK) WHERE toDelete=''1'' WHILE @@rowcount > 0 BEGIN SET ROWCOUNT 100 DELETE FROM Sales WITH(ROWLOCK) WHERE toDelete=''1'' END


He utilizado lo siguiente para eliminar alrededor de 50 millones de registros:

BEGIN TRANSACTION DeleteOperation: DELETE TOP (BatchSize) FROM [database_name].[database_schema].[database_table] IF @@ROWCOUNT > 0 GOTO DeleteOperation COMMIT TRANSACTION

Tenga en cuenta que mantener BatchSize <5000 es menos costoso en recursos.


Llamar a DELETE FROM TableName hará la eliminación completa en una transacción grande. Esto es caro.

Aquí hay otra opción que eliminará filas en lotes:

deleteMore: DELETE TOP(10000) Sales WHERE toDelete=''1'' IF @@ROWCOUNT != 0 goto deleteMore


Lo que quieres es un procesamiento por lotes.

While (select Count(*) from sales where toDelete =1) >0 BEGIN Delete from sales where SalesID in (select top 1000 salesId from sales where toDelete = 1) END

Por supuesto, puede experimentar cuál es el mejor valor para usar en el lote, lo he usado de 500 a 50000 según la tabla. Si usa la eliminación en cascada, probablemente necesite un número más pequeño ya que tiene esos registros secundarios para eliminar.


Mi propia opinión sobre esta funcionalidad sería la siguiente. De esta forma, no hay código repetido y puedes administrar tu tamaño de fragmento.

DECLARE @DeleteChunk INT = 10000 DECLARE @rowcount INT = 1 WHILE @rowcount > 0 BEGIN DELETE TOP (@DeleteChunk) FROM Sales WITH(ROWLOCK) SELECT @rowcount = @@RowCount END


Una manera en que tuve que hacer esto en el pasado es tener un procedimiento almacenado o script que elimina n registros. Repita hasta que termine.

DELETE TOP 1000 FROM Sales WHERE toDelete=''1''