मेरे पास एक बड़ी डेटा टेबल है। इस तालिका में 10 मिलियन रिकॉर्ड हैं।
इस क्वेरी के लिए सबसे अच्छा तरीका क्या है
Delete LargeTable where readTime < dateadd(MONTH,-7,GETDATE())
मेरे पास एक बड़ी डेटा टेबल है। इस तालिका में 10 मिलियन रिकॉर्ड हैं।
इस क्वेरी के लिए सबसे अच्छा तरीका क्या है
Delete LargeTable where readTime < dateadd(MONTH,-7,GETDATE())
जवाबों:
यदि आप उस तालिका की सभी पंक्तियों को हटा रहे हैं, तो सबसे सरल विकल्प ट्रंकट तालिका है, कुछ ऐसा है
TRUNCATE TABLE LargeTable
GO
Truncate तालिका बस तालिका को खाली कर देगी, आप हटाए जा रहे पंक्तियों को सीमित करने के लिए WHERE क्लॉज का उपयोग नहीं कर सकते हैं और कोई ट्रिगर नहीं निकाल दिया जाएगा।
दूसरी ओर यदि आप 80-90 प्रतिशत से अधिक डेटा डिलीट कर रहे हैं, तो कहें कि यदि आपके पास कुल 11 मिलियन पंक्तियाँ हैं और आप 10 मिलियन हटाना चाहते हैं, तो यह होगा कि आप इन 1 मिलियन पंक्तियों को सम्मिलित करें (जो रिकॉर्ड आप रखना चाहते हैं ) एक और स्टेजिंग टेबल पर। इस बड़ी तालिका को काटें और इन 1 मिलियन पंक्तियों को वापस डालें।
या यदि अनुमतियाँ / दृश्य या अन्य ऑब्जेक्ट्स जिसमें यह बड़ी तालिका है क्योंकि उनकी अंतर्निहित तालिका इस तालिका को छोड़ने से प्रभावित नहीं होती है तो आप इन तालिका में अपेक्षाकृत कम मात्रा में पंक्तियाँ प्राप्त कर सकते हैं और इस तालिका को उसी स्कीमा के साथ दूसरी तालिका बना सकते हैं और इन्हें आयात कर सकते हैं पंक्तियाँ इस पूर्व-बड़ी तालिका में वापस आ गईं।
एक आखिरी विकल्प जो मैं सोच सकता हूं, वह है कि आप अपने डेटाबेस को बदल दें Recovery Mode to SIMPLE
और फिर कुछ छोटे लूपों का उपयोग करके पंक्तियों को हटा दें।
DECLARE @Deleted_Rows INT;
SET @Deleted_Rows = 1;
WHILE (@Deleted_Rows > 0)
BEGIN
-- Delete some small number of rows at a time
DELETE TOP (10000) LargeTable
WHERE readTime < dateadd(MONTH,-7,GETDATE())
SET @Deleted_Rows = @@ROWCOUNT;
END
और पुनर्प्राप्ति मोड को पूर्ण में बदलना न भूलें और मुझे लगता है कि आपको इसे पूर्ण रूप से प्रभावी (परिवर्तन या पुनर्प्राप्ति) बनाने के लिए बैकअप लेना होगा।
optimal solution for unknown case
यह सपना नहीं है? दुर्भाग्य से आप हर बीमारी को किसी एक गोली से ठीक नहीं कर सकते हैं; मैंने विभिन्न परिदृश्यों के लिए कुछ संभावित समाधान सुझाए हैं। दुर्भाग्य से यहां कोई स्लिवर बुलेट नहीं है।
@ एम-अली का उत्तर सही है लेकिन यह भी ध्यान रखें कि लॉग्स बहुत बढ़ सकते हैं यदि आप प्रत्येक चंक के बाद लेनदेन नहीं करते हैं और एक चेकपॉइंट करते हैं। यह है कि मैं इसे कैसे करूंगा और इस लेख को ले जाऊंगा http://sqlperformance.com/2013/03/io-subsystem/chunk-deletes संदर्भ के रूप में, प्रदर्शन परीक्षण और ग्राफ़ के साथ:
DECLARE @Deleted_Rows INT;
SET @Deleted_Rows = 1;
WHILE (@Deleted_Rows > 0)
BEGIN
BEGIN TRANSACTION
-- Delete some small number of rows at a time
DELETE TOP (10000) LargeTable
WHERE readTime < dateadd(MONTH,-7,GETDATE())
SET @Deleted_Rows = @@ROWCOUNT;
COMMIT TRANSACTION
CHECKPOINT -- for simple recovery model
END
COMMIT TRANSACTION
और CHECKPOINT
लॉग अभी भी बढ़ रहे हैं। इसे स्पष्ट करने के लिए धन्यवाद।
@Deleted_Rows
10000 से तुलना करना चाहते हैं या आप अनिश्चित रूप से लूप के साथ समाप्त हो सकते हैं क्योंकि यह अनिश्चित रूप से डेटा के छोटे सेट को हटाना है। इसलिए WHILE (@Deleted_Rows = 10000)
- जैसे ही डेटा का एक पूर्ण "पेज" नहीं था उसे हटाने के लिए बंद हो जाएगा। आपके कार्यान्वयन में WHILE (@Deleted_Rows > 0)
, जबकि लूप फिर से निष्पादित करेगा भले ही यह केवल एक पंक्ति को हटाए, और अगले निष्पादन को हटाने के लिए एक पंक्ति या दो भी मिल सकता है - जिसके परिणामस्वरूप एक अनंत लूप होगा।
WHILE
स्वयं लूप के भीतर की तारीख की गणना करते हैं dateadd(MONTH,-7,GETDATE())
:।
WHILE
लूप के विभिन्न पुनरावृत्तियों के बीच हटाए जा सकते हैं ।
आप एक ही क्वेरी को निष्पादित करने के लिए कितनी बार GO + का उपयोग कर सकते हैं।
DELETE TOP (10000) [TARGETDATABASE].[SCHEMA].[TARGETTABLE]
WHERE readTime < dateadd(MONTH,-1,GETDATE());
-- how many times you want the query to repeat
GO 100
GO xx
काम करने वाला है? मुझे एक "संग्रहीत कार्यविधि नहीं मिल सकी" " त्रुटि। GO
कमांड के बिना यह ठीक काम करता है।
@ फ्रैंसिस्को गोल्डनस्टीन, सिर्फ एक मामूली सुधार। आपके द्वारा चर सेट करने के बाद COMMIT का उपयोग किया जाना चाहिए, अन्यथा WHILE को केवल एक बार निष्पादित किया जाएगा:
DECLARE @Deleted_Rows INT;
SET @Deleted_Rows = 1;
WHILE (@Deleted_Rows > 0)
BEGIN
BEGIN TRANSACTION
-- Delete some small number of rows at a time
DELETE TOP (10000) LargeTable
WHERE readTime < dateadd(MONTH,-7,GETDATE())
SET @Deleted_Rows = @@ROWCOUNT;
COMMIT TRANSACTION
CHECKPOINT -- for simple recovery model
END
M.Ali की यह भिन्नता मेरे लिए ठीक काम कर रही है। यह कुछ को हटाता है, लॉग को साफ करता है और दोहराता है। मैं लॉग बढ़ता देख रहा हूँ, छोड़ दो और शुरू करो।
DECLARE @Deleted_Rows INT;
SET @Deleted_Rows = 1;
WHILE (@Deleted_Rows > 0)
BEGIN
-- Delete some small number of rows at a time
delete top (100000) from InstallLog where DateTime between '2014-12-01' and '2015-02-01'
SET @Deleted_Rows = @@ROWCOUNT;
dbcc shrinkfile (MobiControlDB_log,0,truncateonly);
END
# of rows
लिए एक समय में हटाने के लिए और WHERE
क्लॉज को भी संशोधित किया । एक जादू की तरह काम करता है!
यदि आप विभाजन को लागू करने के लिए तैयार (और सक्षम) हैं, तो यह बहुत ही कम समय के साथ बड़ी मात्रा में डेटा को हटाने के लिए एक प्रभावी तकनीक है। हालांकि एक बार के व्यायाम के लिए लागत प्रभावी नहीं है।
मैं मिनटों के मामले में अपनी 21 मिलियन पंक्तियों की तालिका से 19 मिलियन पंक्तियों को हटाने में सक्षम था । यहाँ मेरा दृष्टिकोण है।
यदि आपके पास इस मेज पर एक ऑटो-इन्क्रिमेंटिंग प्राथमिक कुंजी है , तो आप इस प्राथमिक कुंजी का उपयोग कर सकते हैं।
बड़ी तालिका के प्राथमिक मान का न्यूनतम मान प्राप्त करें जहां readTime <dateadd (MONTH; -7, GETDATE ())। (रीड टाइम पर इंडेक्स जोड़ें, यदि पहले से मौजूद नहीं है, तो यह इंडेक्स वैसे भी चरण 3 में तालिका के साथ हटा दिया जाएगा)। इसे एक चर 'min_primary' में संग्रहीत करें
प्राथमिक चरणों> min_primary को मेज़िंग टेबल (स्मृति तालिका में यदि पंक्तियों की संख्या बड़ी नहीं है) वाली सभी पंक्तियों को सम्मिलित करें।
बड़ी टेबल गिरा दो।
तालिका को पुन: बनाएँ। स्टेजिंग टेबल से लेकर मेन टेबल तक सभी पंक्तियों को कॉपी करें।
मंचन तालिका गिराएं।
आप कुछ समय के लूप का उपयोग करके छोटे बैचों को हटा सकते हैं, कुछ इस तरह से:
DELETE TOP (10000) LargeTable
WHERE readTime < dateadd(MONTH,-7,GETDATE())
WHILE @@ROWCOUNT > 0
BEGIN
DELETE TOP (10000) LargeTable
WHERE readTime < dateadd(MONTH,-7,GETDATE())
END
एक और उपयोग:
SET ROWCOUNT 1000 -- Buffer
DECLARE @DATE AS DATETIME = dateadd(MONTH,-7,GETDATE())
DELETE LargeTable WHERE readTime < @DATE
WHILE @@ROWCOUNT > 0
BEGIN
DELETE LargeTable WHERE readTime < @DATE
END
SET ROWCOUNT 0
वैकल्पिक;
यदि लेन-देन लॉग सक्षम है, तो लेन-देन लॉग अक्षम करें।
ALTER DATABASE dbname SET RECOVERY SIMPLE;
यदि आप SQL सर्वर 2016 या उच्चतर का उपयोग कर रहे हैं और यदि आपकी तालिका में स्तंभों के आधार पर विभाजन बनाए गए हैं जिन्हें आप हटाने के लिए प्रयास कर रहे हैं (उदाहरण के लिए टाइमस्टैम्प कॉलम), तो आप विभाजन द्वारा डेटा को हटाने के लिए इस नई कमांड का उपयोग कर सकते हैं।
के साथ TRUNCATE टेबल (विभाजन ({|}}, ... n]))
यह केवल चुने हुए विभाजन में डेटा को हटाएगा और तालिका के भाग से डेटा को हटाने के लिए सबसे कुशल तरीका होना चाहिए क्योंकि यह लेनदेन लॉग नहीं बनाएगा और नियमित ट्रंकट के रूप में तेजी से किया जाएगा, लेकिन सभी डेटा हटाए बिना मेज से।
दोष यह है कि यदि आपकी तालिका विभाजन के साथ सेटअप नहीं है, तो आपको पुराने स्कूल जाने और नियमित दृष्टिकोण के साथ डेटा को हटाने की आवश्यकता है और फिर विभाजन के साथ तालिका को फिर से बनाएं ताकि आप भविष्य में ऐसा कर सकें, जो मैंने किया है। मैंने सम्मिलन प्रक्रिया में विभाजन निर्माण और विलोपन को जोड़ा। मेरे पास 500 मिलियन पंक्तियों के साथ तालिका थी इसलिए यह विलोपन समय को कम करने का एकमात्र विकल्प था।
अधिक जानकारी के लिए नीचे दिए गए लिंक देखें: https://docs.microsoft.com/en-us/sql/t-sql/statements/truncate-table-transact-sql?view=sql-server7
विभाजन के साथ SQL सर्वर 2016 ट्रंकट टेबल
नीचे मैंने पहले डेटा को हटाने के लिए क्या किया था इससे पहले कि मैं इसमें आवश्यक डेटा के साथ विभाजन के साथ तालिका को पुनः बना सकता हूं। यह क्वेरी डेटा डिलीट होने तक निर्दिष्ट समय विंडो के दौरान दिनों तक चलेगी।
:connect <<ServerName>>
use <<DatabaseName>>
SET NOCOUNT ON;
DECLARE @Deleted_Rows INT;
DECLARE @loopnum INT;
DECLARE @msg varchar(100);
DECLARE @FlagDate datetime;
SET @FlagDate = getdate() - 31;
SET @Deleted_Rows = 1;
SET @loopnum = 1;
/*while (getdate() < convert(datetime,'2018-11-08 14:00:00.000',120))
BEGIN
RAISERROR( 'WAIT for START' ,0,1) WITH NOWAIT
WAITFOR DELAY '00:10:00'
END*/
RAISERROR( 'STARTING PURGE' ,0,1) WITH NOWAIT
WHILE (1=1)
BEGIN
WHILE (@Deleted_Rows > 0 AND (datepart(hh, getdate() ) >= 12 AND datepart(hh, getdate() ) <= 20)) -- (getdate() < convert(datetime,'2018-11-08 19:00:00.000',120) )
BEGIN
-- Delete some small number of rows at a time
DELETE TOP (500000) dbo.<<table_name>>
WHERE timestamp_column < convert(datetime, @FlagDate,102)
SET @Deleted_Rows = @@ROWCOUNT;
WAITFOR DELAY '00:00:01'
select @msg = 'ROWCOUNT' + convert(varchar,@Deleted_Rows);
set @loopnum = @loopnum + 1
if @loopnum > 1000
begin
begin try
DBCC SHRINKFILE (N'<<databasename>>_log' , 0, TRUNCATEONLY)
RAISERROR( @msg ,0,1) WITH NOWAIT
end try
begin catch
RAISERROR( 'DBCC SHRINK' ,0,1) WITH NOWAIT
end catch
set @loopnum = 1
end
END
WAITFOR DELAY '00:10:00'
END
select getdate()
यदि मैं बिना लूप के कहता हूं, तो मैं GOTO
sql सर्वर का उपयोग करके बड़ी मात्रा में रिकॉर्ड हटाने के लिए स्टेटमेंट का उपयोग कर सकता हूं । exa।
IsRepeat:
DELETE TOP (10000)
FROM <TableName>
IF @@ROWCOUNT > 0
GOTO IsRepeat
इस तरह आप छोटे आकार के डिलीट के साथ बड़ी मात्रा में डेटा हटा सकते हैं।
अगर मुझे और जानकारी चाहिए तो मुझे बताएं।