2008-09-21 16 views
13

अपडेट करें मेरे पास PostgresQL में एक बहुत बड़ी डेटाबेस तालिका है और "कॉपी" जैसे कॉलम हैं। प्रत्येक नई पंक्ति अनिश्चित हो जाती है और बाद में पृष्ठभूमि प्रोग्राम द्वारा दूसरी चीज़ में दोहराया जाएगा। उस तालिका पर आंशिक अनुक्रमणिका है "btree (आईडी) जहां replicated = 0"। पृष्ठभूमि प्रोग्राम अधिकांश 2000 प्रविष्टियों (LIMIT 2000) के लिए एक चयन करता है, उन पर काम करता है और फिर 2000 तैयार एसक्यूएल-कमांड का उपयोग करके एक लेनदेन में परिवर्तन करता है।बहुत बड़ी पोस्टग्रेएसक्यूएल डेटाबेस तालिका को कुशलतापूर्वक

अब समस्या यह है कि मैं उपयोगकर्ता को इस प्रतिकृति-मूल्य को रीसेट करने का विकल्प देना चाहता हूं, इसे फिर से शून्य बना दें।

एक अद्यतन तालिका सेट दोहराया = 0;

संभव नहीं है:

  • यह बहुत ज्यादा समय
  • लेता है यह MVCC
  • यह एक लेन-देन में किया जाता है की वजह से तालिका के के आकार डुप्लिकेट: यह या तो विफल रहता है या के माध्यम से चला जाता है।

मुझे वास्तव में इस मामले के लिए लेनदेन-सुविधाओं की आवश्यकता नहीं है: यदि सिस्टम नीचे चला जाता है, तो यह केवल इसके कुछ हिस्सों को संसाधित करेगा।

कई अन्य समस्याओं: एक

update set replicated=0 where id >10000 and id<20000 

कर भी बुरा है: यह सब पूरी तालिका जो बहुत धीमी है पर एक अनुक्रमिक स्कैन करता है। यदि यह ऐसा नहीं कर रहा था, तो यह अभी भी धीमा होगा क्योंकि यह बहुत अधिक मांग करेगा।

मुझे वास्तव में जो चाहिए वह सभी पंक्तियों के माध्यम से जाने, उन्हें बदलने और एक विशाल लेनदेन से बंधे होने का एक तरीका है।

अजीब, एक

UPDATE table 
    SET replicated=0 
WHERE ID in (SELECT id from table WHERE replicated= LIMIT 10000) 

भी धीमी है, हालांकि यह एक अच्छी बात होना चाहिए: डिस्क-क्रम में तालिका को ध्यान से ...

(कि उस मामले में वहाँ भी था नोट एक सूचकांक है कि इस कवर)

(MySQL की तरह एक अद्यतन LIMIT में PostgreSQL के लिए उपलब्ध नहीं)

BTW है: वास्तविक समस्या अधिक जटिल है और हम एक के बारे में बात कर रहे हैं यहां एम्बेडेड सिस्टम जो पहले से ही तैनात है, इसलिए रिमोट स्कीमा परिवर्तन मुश्किल हैं, लेकिन संभव है दुर्भाग्यवश यह पोस्टग्रेसक्यूएल 7.4 है।

मैं जिस पंक्तियों के बारे में बात कर रहा हूं वह है उदा। 90000000. डेटाबेस का आकार कई दर्जन गीगाबाइट हो सकता है।

डेटाबेस में केवल 5 टेबल हैं, एक बहुत बड़ा है। लेकिन यह खराब डिज़ाइन नहीं है, क्योंकि ये एम्बेडेड बॉक्स केवल एक प्रकार की इकाई के साथ काम करते हैं, यह एक ईआरपी-सिस्टम या ऐसा कुछ नहीं है!

कोई विचार?

उत्तर

8

इस प्रतिकृति मूल्य को स्टोर करने के लिए एक नई तालिका जोड़ने के बारे में (और मुख्य रिकॉर्ड में प्रत्येक रिकॉर्ड को जोड़ने के लिए प्राथमिक कुंजी)। फिर आप बस प्रतिलिपि किए गए आइटम के लिए एक रिकॉर्ड जोड़ते हैं, और प्रतिकृति ध्वज को हटाने के लिए रिकॉर्ड हटाते हैं।(या शायद दूसरी तरफ - प्रत्येक गैर-प्रतिकृति रिकॉर्ड के लिए एक रिकॉर्ड, जो सामान्य मामला है) के आधार पर।

यह उस मामले को भी सरल बना देगा जब आप उन्हें 0 पर वापस सेट करना चाहते हैं, क्योंकि आप केवल तालिका को छोटा कर सकते हैं (जो डिस्क पर टेबल आकार को शून्य करता है, आपको अंतरिक्ष को मुक्त करने के लिए वैक्यूम भी नहीं करना पड़ता है)

+0

यह एक बहुत अच्छा विचार है, हालांकि दुर्भाग्यवश दुर्भाग्यवश एक स्कीमा परिवर्तन (एक लम्बे समय से अद्यतन प्रक्रिया) की आवश्यकता है। मुझे इस दृष्टिकोण के बारे में वास्तव में क्या पसंद है यह वास्तव में, वर्तमान आंशिक सूचकांक आंतरिक रूप से इस विचार के समान ही है! केवल अधिक लचीला और प्रबंधनीय। – Christian

3

आप पूरे मेज ही नहीं, कुछ ऐसी पंक्तियां हैं रीसेट करने का प्रयास कर रहे हैं, यह आम तौर पर तेजी से (अत्यंत बड़े डेटासेट पर है - नियमित रूप से टेबल पर नहीं) के लिए बस CREATE TABLE bar AS SELECT everything, but, copied, 0 FROM foo, और फिर टेबल स्वैप और पुराने ड्रॉप एक। जाहिर है आपको यह सुनिश्चित करने की आवश्यकता होगी कि आप मूल तालिका में कुछ भी नहीं डालते हैं जबकि आप ऐसा कर रहे हैं। आपको भी उस इंडेक्स को फिर से बनाना होगा।

संपादित: आदेश तालिका ताला से बचने के लिए एक सामान्य सुधार आप 14 गीगाबाइट नकल करते हुए:

lock ; 
create a new table, bar; 
swap tables so that all writes go to bar; 
unlock; 
create table baz as select from foo; 
drop foo; 
create the index on baz; 
lock; 
insert into baz from bar; 
swap tables; 
unlock; 
drop bar; 

(राईट हो जब तुम नकल कर रहे हैं, और उनमें बाद बात के बाद सम्मिलित)।

1

यह छद्म कोड है। आपको 400 एमबी (इन्ट्स के लिए) या 800 एमबी (बिगिनट्स के लिए) अस्थायी फ़ाइल की आवश्यकता होगी (यदि आप एक समस्या है तो आप इसे zlib के साथ संपीड़ित कर सकते हैं)। वैक्यूम के लिए इसे टेबल के लगभग 100 स्कैन की आवश्यकता होगी। लेकिन यह 1% से अधिक तालिका (किसी भी समय 1000000 मृत पंक्तियों पर) को नहीं फेंक देगा। आप अधिक टेबल ब्लोट के लिए कम स्कैन भी व्यापार कर सकते हैं।

// write all ids to temporary file in disk order     
// no where clause will ensure disk order 
$file = tmpfile(); 
for $id, $replicated in query("select id, replicated from table") { 
     if ($replicated<>0) { 
       write($file,&$id,sizeof($id)); 
     } 
} 

// prepare an update query 
query("prepare set_replicated_0(bigint) as 
     update table set replicated=0 where id=?"); 

// reread this file, launch prepared query and every 1000000 updates commit 
// and vacuum a table 
rewind($file); 
$counter = 0; 
query("start transaction"); 
while read($file,&$id,sizeof($id)) { 
     query("execute set_replicated_0($id)"); 
     $counter++; 
     if ($counter % 1000000 == 0) { 
       query("commit"); 
       query("vacuum table"); 
       query("start transaction"); 
     } 
} 
query("commit"); 
query("vacuum table"); 
close($file); 
2

आप की संभावना अंतरिक्ष उपयोग के समस्या को ठीक नहीं कर सकते हैं (यह अस्थायी है, सिर्फ एक निर्वात जब तक) आप शायद वास्तव में घड़ी समय के संदर्भ में प्रक्रिया में तेजी लाने सकता है। तथ्य यह है कि PostgreSQL एमवीसीसी का उपयोग करता है इसका मतलब है कि आपको नई डाली गई पंक्तियों से संबंधित किसी भी मुद्दे के बिना ऐसा करने में सक्षम होना चाहिए। चयन के रूप में बनाई गई तालिका कुछ प्रदर्शन समस्याओं के आसपास मिल जाएगी, लेकिन तालिका के निरंतर उपयोग की अनुमति नहीं देगी, और उतनी ही जगह लेती है। बस इंडेक्स को डुबोएं, और इसे पुनर्निर्माण करें, फिर वैक्यूम करें।

drop index replication_flag; 
update big_table set replicated=0; 
create index replication_flag on big_table btree(ID) WHERE replicated=0; 
vacuum full analyze big_table; 
1

मुझे लगता है कि आपके पोस्टग्रेज़ को संस्करण 8.X में बदलना बेहतर है। शायद पोस्टग्रेज़ का निम्न संस्करण कारण है। नीचे यह प्रश्न भी आज़माएं। मुझे उम्मीद है कि यह मदद कर सकता है।

UPDATE table1 SET name = table2.value 
FROM table2 
WHERE table1.id = table2.id; 
0

मुझे लगता है कि आपको क्या करना है ए। 2000 रिकॉर्ड पीके मान को उसी मानक सीमा के साथ एक अस्थायी तालिका में कॉपी करें, आदि बी। उसी 2000 रिकॉर्ड का चयन करें और कर्सर में आवश्यक संचालन करें जैसा कि यह है। सी। यदि सफल हो, तो temp तालिका में रिकॉर्ड्स के विरुद्ध एक एकल अद्यतन क्वेरी चलाएं। अस्थायी तालिका साफ़ करें और एक बार फिर से चलाएं। डी। यदि असफल हो, तो अद्यतन क्वेरी को चलाने के बिना temp तालिका साफ़ करें। सरल, कुशल और विश्वसनीय। सम्मान, केटी

संबंधित मुद्दे