2012-06-27 19 views
20

मान लें कि हमारे पास तालिका बिक्री है जिसमें 30 कॉलम और 500,000 पंक्तियां हैं। मैं तालिका में 400,000 को हटाना चाहता हूं (जहां "toDelete='1'")।500,000+ पंक्तियों तालिका में ट्रंकेट तालिका का उपयोग न करने के दौरान पंक्तियों को कुशलता से हटाएं

लेकिन मैं कुछ कमी है:

  • तालिका पढ़ा जाता है/लिखा "अक्सर" और मैं नहीं करना चाहते हैं एक लंबे "हटाएँ" एक लंबे समय लेने के लिए और बहुत लंबा
  • के लिए तालिका लॉक करने के लिए
  • मैं (एक TRUNCATE साथ की तरह) लेनदेन लॉग को छोड़ करने की जरूरत है, लेकिन जब एक "DELETE ... WHERE..." कर (मैं एक शर्त लगाने की जरूरत है), लेकिन किसी भी तरह से यह करने के लिए नहीं मिला है ...

किसी भी सलाह होगा

को बदलने के लिए आपका स्वागत है
DELETE FROM Sales WHERE toDelete='1' 

कुछ और विभाजित & संभवतः लेनदेन लॉग मुक्त।

+2

तुम क्यों लेनदेन लॉग को छोड़ने के लिए की जरूरत है? –

+1

इसकी सराहना करेंगे कि यदि आप पूरा कर लेंगे तो आप इष्टतम समाधान पोस्ट करेंगे (या कम से कम वह जो आपके लिए सबसे अच्छा काम करता है)। –

+0

@thecoon: मैं निश्चित रूप से करूँगा। आपके विभिन्न, पूरक उत्तरों के लिए सभी को धन्यवाद। –

उत्तर

5

एक तरह से मुझे अतीत में ऐसा करना पड़ा है एक संग्रहीत प्रक्रिया या स्क्रिप्ट है जो n रिकॉर्ड्स हटा देती है। पूरा होने तक दोहराएं।

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

हर बार जब आप डेटाबेस को छोटा करते हैं, तो बिल्ली का बच्चा मर जाता है! [http://www.sqlskills.com/BLOGS/PAUL/post/Why-you-should-not-shrink-your-data-files.aspx](http://www.sqlskills.com/BLOGS/PAUL/ पोस्ट/क्यों-आपको-नहीं-नहीं-हटना-आपकी-डेटा-फाइल.aspx) –

+0

स्पष्टीकरण के लिए (जैसा कि यह एक हैक है), मैं उस समय अपनी लॉगिंग निर्देशिका पर डिस्क-स्पेस बाधाओं के कारण ऐसा कर रहा था लॉक करने के बजाए। मुझे लगता है कि इसके साथ लॉक-अवधि समान है, बस लंबे समय तक फैलाएं :) – Cylindric

+0

डेटाबेस को हटाना? नहीं, कृपया ऐसा मत करो। उम्मीद है कि आप चेकपॉइंट या कुछ मतलब था ... –

1

आप तो यह पूरे तालिका लॉक नहीं करेगा यह एक ROWLOCK संकेत देने के लिए प्रयास करना चाहिए। हालांकि, अगर आप बहुत सारी पंक्तियां लॉक करते हैं तो एस्केलेशन होगा।

इसके अलावा, सुनिश्चित करें कि आपके पास कॉलम पर एक गैर-क्लस्टर फ़िल्टर अनुक्रमणिका (केवल 1 मानों के लिए) है। यदि संभव हो तो इसे थोड़ा कॉलम बनाएं, वर्चर नहीं (या अब यह क्या है)।

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

आखिरकार, आप तालिका में फिर से प्रयास करने और हिस्सों में हटाने की कोशिश कर सकते हैं।

अपडेट किया गया के बाद से while लूप में और हिस्सा हटाए गए नए गुलाबी यहाँ हैं, मैं भी मेरी संस्करण में फेंक देंगे (मेरे पिछले जवाब के साथ संयुक्त):

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 
+2

' सेट ROWCOUNT' [एसक्यूएल 2012 में बहिष्कृत] है (http://msdn.microsoft.com/en-us/library/ms143729.aspx)। – ErikE

27

DELETE FROM TableName कॉलिंग करना होगा एक बड़े लेनदेन में पूरी हटा दें। ये कीमती है।

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

ओह मेरे! मैंने कभी कैसे महसूस नहीं किया कि आप 'DELETE' कथन में 'TOP()' अभिव्यक्ति डाल सकते हैं? मेरे कार्यात्मक रूप से समान उत्तर से अधिक संक्षिप्त; आपके लिए +1 सर! – MatBailie

+8

सचमुच मुझे यह भी याद नहीं आया कि आप SQL 2008 में लेबल का उपयोग कर सकते हैं। I 'एक WHILE कथन देखें।' WHILE 1 = 1 BEGIN; हटाएं ...; अगर @@ रोकाउंट = 0 BREAK; अंत; 'यह मेरे लिए अगले एसक्यूएल लेखक के लिए स्पष्ट है जो एक लूप के साथ आता है, भयानक गोटो को समझने के बजाए। – ErikE

10

क्या आप चाहते हैं बैच प्रोसेसिंग है:

यहाँ एक और विकल्प है जिसके बैचों में पंक्तियों का हटाया जाएगा। तालिका के आधार पर 50000 -

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 
बेशक आप प्रयोग कर सकते हैं जो बैच के लिए उपयोग करने के लिए सबसे अच्छा मूल्य है

, मैं से 500 का उपयोग किया है। यदि आप कास्केड डिलीट का उपयोग करते हैं, तो आपको शायद एक छोटी संख्या की आवश्यकता होगी क्योंकि आपके पास उन बच्चों के रिकॉर्ड को हटाने के लिए है।

+0

'@@ rowcount' का उपयोग किए जाने पर बार-बार कॉल 'COUNT (*)' अनिवार्य प्रतीत होता है। लेकिन यह अन्य आरडीबीएमएस के लिए एक बहुत ही पोर्टेबल समाधान है ... – MatBailie

+1

सच है, मैं इसे जल्दबाजी में मार डाला और पूरी तरह अनुकूलित करने में समय नहीं लगा। और मुझे वास्तव में इसका उपयोग करने के लिए उपयोग नहीं किया जाता है शीर्ष खोजशब्द, कभी-कभी अभ्यास के वर्षों के खिलाफ जाने के लिए मुश्किल है। – HLGEM

+0

बस हटा दिया गया: आखिरी हटाए गए अधिक लेबल पर क्योंकि यह मुझे एक त्रुटि लेबल पहले ही घोषित कर दिया गया था। इस छोटे सुधार के साथ ठीक काम किया। –

0

इस कार्यक्षमता पर मेरा अपना लेना निम्नानुसार होगा। इस तरह कोई दोहराया कोड नहीं है और आप अपने खंड आकार का प्रबंधन कर सकते हैं।

DECLARE @DeleteChunk INT = 10000 
DECLARE @rowcount INT = 1 

WHILE @rowcount > 0 
BEGIN 

    DELETE TOP (@DeleteChunk) FROM Sales WITH(ROWLOCK) 

    SELECT @rowcount = @@RowCount 
END 
0

मैं लगभग 50 मिलियन रिकॉर्ड नष्ट करने के लिए नीचे दिए गए का इस्तेमाल किया है -

BEGIN TRANSACTION  
    DeleteOperation: 
    DELETE TOP (BatchSize) 
    FROM [database_name].[database_schema].[database_table] 

    IF @@ROWCOUNT > 0 
    GOTO DeleteOperation 
COMMIT TRANSACTION 

कृपया ध्यान दें कि BatchSize < 5000 रखने कम संसाधनों पर महंगा है।

0

जैसा कि मुझे लगता है कि बड़ी संख्या में रिकॉर्ड्स को हटाने का सबसे अच्छा तरीका है Primary Key द्वारा इसे हटाना। (Primary Keysee here)

तो आपको tsql स्क्रिप्ट उत्पन्न करना होगा जिसमें हटाने के लिए लाइनों की पूरी सूची और इस स्क्रिप्ट को निष्पादित करने के बाद।

नीचे दिए गए उदाहरण कोड के लिए वाला है कि फाइल

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 

ouput फाइल उत्पन्न

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

की तरह रिकॉर्ड वाला है और अब आप इस स्क्रिप्ट पर अमल करने में SQLCMD उपयोगिता का उपयोग करने के लिए है है।

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

आप इस दृष्टिकोण पा सकते हैं यहाँ explaned https://www.mssqltips.com/sqlservertip/3566/deleting-historical-data-from-a-large-highly-concurrent-sql-server-database-table/