Používání serveru SQL Server 2005.
Provádím obrovský ODSTRANIT OD bez klauzulí. Je to v zásadě ekvivalentní příkazu TRUNCATE TABLE - kromě toho, že nemůžu používat TRUNCATE. Problém je v tom, že tabulka je obrovská - 10 milionů řádků a dokončení trvá přes hodinu. Existuje nějaký způsob, jak zrychlit bez:
T-log je již na samostatném disku.
Jakékoli návrhy vítány!
To, co můžete udělat, je hromadné mazání takto:
SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
DELETE TOP (xxx) MyTable
Kde xxx je, řekněme, 50000
Úprava tohoto, pokud chcete odstranit velmi vysoké procento řádků ...
SELECT col1, col2, ... INTO #Holdingtable
FROM MyTable WHERE ..some condition..
SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
DELETE TOP (xxx) MyTable WHERE ...
INSERT MyTable (col1, col2, ...)
SELECT col1, col2, ... FROM #Holdingtable
Dalo by se použít klauzuli TOP, abyste to snadno provedli:
WHILE (1=1)
BEGIN
DELETE TOP(1000) FROM table
IF @@ROWCOUNT < 1 BREAK
END
Souhlasím s návrhy na rozdělení vašich deletů do zvládnutelných bloků, pokud nejste schopni používat TRUNCATE, a líbí se mi návrh na přetažení/vytvoření pro jeho originalitu, ale jsem zvědavý na následující komentář ve vaší otázce:
Je to v podstatě ekvivalentní příkazu TRUNCATE TABLE - kromě toho, že nemám dovoleno používat TRUNCATE
Hádám, že důvod tohoto omezení souvisí s bezpečností, která musí být udělena pro přímé zkrácení tabulky, a se skutečností, že by vám to umožnilo zkrátit jiné tabulky než ty, kterých se týkáte.
Za předpokladu, že tomu tak je, jsem zvědavý, zda by mít vytvořenou uloženou proceduru, která používá TRUNCATE TABLE a používá "EXECUTE AS", bylo považováno za schůdnou alternativu k udělení bezpečnostních práv nezbytných k přímému zkrácení tabulky.
Doufejme, že vám to poskytne rychlost, kterou potřebujete, a zároveň vyřešíte bezpečnostní obavy, které může mít vaše společnost při přidávání účtu do role db_ddladmin.
Další výhodou použití uložené procedury tímto způsobem je, že samotná uložená procedura může být uzamčena, takže ji mohou používat pouze konkrétní účty.
Pokud to z nějakého důvodu není přijatelné řešení a vaše potřeba mít data v této tabulce odstraněna je něco, co je třeba udělat jednou denně/hodinu/atd., Chtěl bych požádat o vytvoření úlohy SQL Agent pro zkrácení tabulky každý den v plánovaném čase.
Snad to pomůže!
Kromě zkrácení .. vám může pomoci pouze smazání v dávkách.
Mohli byste zrušit tabulku a znovu ji vytvořit, se všemi omezeními a indexy, samozřejmě. V Management Studio máte možnost skriptovat tabulku, kterou chcete přetáhnout a vytvořit, takže by měla být triviální možností. Ale to jen pokud máte povoleno provádět akce DDL, což je podle mého názoru opravdu nemožné.
Vzhledem k tomu, že tato otázka je tak důležitým odkazem, odesílám tento kód, který mi opravdu pomohl porozumět vymazání pomocí smyček a také zasílání zpráv v rámci smyčky ke sledování pokroku.
Dotaz je upraven z tato duplicitní otázka. Kredit za @ RLF za základnu dotazu.
CREATE TABLE #DelTest (ID INT IDENTITY, name NVARCHAR(128)); -- Build the test table
INSERT INTO #DelTest (name) SELECT name FROM sys.objects; -- fill from system DB
SELECT COUNT(*) TableNamesContainingSys FROM #deltest WHERE name LIKE '%sys%'; -- check rowcount
go
DECLARE @HowMany INT;
DECLARE @RowsTouched INT;
DECLARE @TotalRowCount INT;
DECLARE @msg VARCHAR(100);
DECLARE @starttime DATETIME
DECLARE @currenttime DATETIME
SET @RowsTouched = 1; -- Needs to be >0 for loop to start
SET @TotalRowCount=0 -- Total rows deleted so far is 0
SET @HowMany = 5; -- Variable to choose how many rows to delete per loop
SET @starttime=GETDATE()
WHILE @RowsTouched > 0
BEGIN
DELETE TOP (@HowMany)
FROM #DelTest
WHERE name LIKE '%sys%';
SET @RowsTouched = @@ROWCOUNT; -- Rows deleted this loop
SET @TotalRowCount = @[email protected]; -- Increment Total rows deleted count
SET @currenttime = GETDATE();
SELECT @msg='Deleted ' + CONVERT(VARCHAR(9),@TotalRowCount) + ' Records. Runtime so far is '+CONVERT(VARCHAR(30),DATEDIFF(MILLISECOND,@starttime,@currenttime))+' milliseconds.'
RAISERROR(@msg, 0, 1) WITH NOWAIT; -- Print message after every loop. Can't use the PRINT function as SQL buffers output in loops.
END;
SELECT COUNT(*) TableNamesContainingSys FROM #DelTest WHERE name LIKE '%sys%'; -- Check row count after loop finish
DROP TABLE #DelTest;