MySQL में कॉलम को बड़ी टेबल पर कैसे जोड़ें


13

मैं PHP डेवलपर हूं इसलिए सख्त मत बनो। मेरे पास एक बड़ी मेज है ~ 5.5 जीबी डंप। हमारे पीएम ने नई सुविधा देने के लिए इसमें नया कॉलम बनाने का फैसला किया। तालिका InnoDB है तो मैंने क्या कोशिश की:

  1. तालिका लॉक के साथ स्क्रीन में परिवर्तन तालिका। ~ 30 घंटे और कुछ भी नहीं लिया। इसलिए मैंने इसे रोक दिया। पहले मैंने एक गलती की क्योंकि मैंने सभी लेन-देन को समाप्त नहीं किया था लेकिन दूसरी बार कोई मल्टीकॉक नहीं था। स्थिति थी copy to tmp table

  2. चूंकि मुझे इस तालिका के लिए विभाजन को लागू करने की आवश्यकता है, इसलिए हम एक ही नाम और नई संरचना के साथ डंप, नाम बदलने और तालिका बनाने का निर्णय लेते हैं। लेकिन डंप सख्त प्रतिलिपि बना रहा है (कम से कम मुझे कुछ और नहीं मिला)। इसलिए मैंने इसके साथ एक नया कॉलम डंप करने sedऔर इसे क्वेरी करने के लिए जोड़ा । लेकिन कुछ अजीब त्रुटियां शुरू हुईं। मेरा मानना ​​है कि यह चारसेट के कारण हुआ। Utf-8 और फ़ाइल में तालिका हमारे बाद ascii बन गई sed। इसलिए मुझे 30% डेटा पर त्रुटियां (अज्ञात कमांड '\') मिलीं। तो यह भी एक बुरा तरीका है।

इसे पूरा करने और गति प्रदर्शन के लिए अन्य विकल्प क्या हैं (मैं इसे php स्क्रिप्ट के साथ कर सकता हूं, लेकिन इसमें उम्र लग जाएगी)। INSERT SELECTइस मामले में प्रदर्शन क्या होगा ।

किसी भी अग्रिम के लिए धन्यवाद।

जवाबों:


12

MySQL कार्यक्षेत्र का उपयोग करें । आप एक तालिका पर राइट-क्लिक कर सकते हैं और "Send to SQL Editor" -> "स्टेटमेंट बनाएँ" का चयन करें। इस तरह से कोई तालिका "गुण" जोड़ना ( CHARSETया सहित COLLATE) नहीं भूल जाएगा ।
इस डेटा की बड़ी मात्रा के साथ मैं या तो तालिका या आपके द्वारा उपयोग की जाने वाली डेटा संरचना की सफाई करने की सलाह दूंगा (एक अच्छा DBA काम आता है)। यदि संभव न हो तो:

  • तालिका का नाम बदलें ( ALTER) और CREATEस्क्रिप्ट के साथ एक नया बनाएं जो आपको वर्कबेंच से मिलता है। आप उस क्वेरी को उस नए क्षेत्र के साथ भी बढ़ा सकते हैं, जिसकी आपको आवश्यकता है
  • पुराने तालिका से नए में डेटा लोड करें:
    SET FOREIGN_KEY_CHECKS = 0;
    SET UNIQUE_CHECKS = 0;
    SET AUTOCOMMIT = 0;
    INSERT INTO new_table (fieldA, fieldB, fieldC, ..., fieldN)
       SELECT fieldA, fieldB, fieldC, ..., fieldN
       FROM old_table
    SET UNIQUE_CHECKS = 1;
    SET FOREIGN_KEY_CHECKS = 1;
    COMMIT;

    इस तरह आप रिकॉर्ड द्वारा रिकॉर्ड चलाने के लिए अनुक्रमण / आदि से बचते हैं। तालिका में "अपडेट" अभी भी धीमा होगा (चूंकि डेटा की मात्रा बहुत बड़ी है) लेकिन यह सबसे तेज़ तरीका है जिसके बारे में मैं सोच सकता हूं।

    संपादित करें: उपरोक्त नमूना क्वेरी में प्रयुक्त कमांड के बारे में विवरण प्राप्त करने के लिए इस लेख को पढ़ें ;)

मेरे विकल्प ठीक हैं। और मुझे मिल गया SET NAMES utf8और COLLATIONडेटा के 30% के बाद भ्रष्ट क्यों idk हुंह .लेकिन sed। मुझे लगता है कि बल्क लोड सबसे तेज होगा लेकिन शायद कुछ और मौजूद हो जो मुझे याद आ रहा है। धन्यवाद मार्क
ineersa

1
@ineersa डेटा भ्रष्टाचार के कई कारण हो सकते हैं: जैसे आपने फ़ाइल को एक संपादक के साथ खोला है जो सभी वर्णों का समर्थन नहीं करता है और इसे सहेजा है। या, जिस तरह से आप डंप से आयात करने का प्रयास करते हैं वह डेटा को दूषित कर देता है (यह छोटी गाड़ी है और फ़ाइल को ठीक से नहीं पढ़ सकता है)। या, एक ही व्यक्ति कुछ डेटा के एक भाग को अभिव्यक्ति के रूप में पहचान सकता है (जैसे "james \ robin" == "\ r" को अभिव्यक्ति के रूप में) या कमांड, आदि। यही कारण है कि मैं कभी भी डंप का उपयोग करने की सलाह नहीं देता, बाइनरी डेटा डंप टूल के साथ भी नहीं केवल, dev.mysql.com/doc/refman/5.6/en/mysqldump.html (या MS SQL सर्वर के लिए BCP) के साथ भी नहीं । यह बहुत बार गलत हो जाता है ...

हाँ मैं हेक्स-बूँद के साथ की कोशिश की। यह मदद नहीं करता है। इसके अलावा आप कुछ नामों (सभी में नहीं) में कमांड के रूप में sed mysql आइडेंटिटी का उपयोग करने के बाद ही सही। अजीब और छोटी बात है। आज रात थोक लोड की कोशिश करेंगे। आशा है कि यह कम से कम 10-15 बजे में किया जाएगा।
ineersa

@ineersa आशा है कि यह होगा। आप डेटा के केवल भाग को जोड़ने का भी प्रयास कर सकते हैं, मान लें कि इसका 10% यह देखने के लिए कि कितना समय लगता है - और पूरे लेनदेन के लिए एक अनुमान है। यह एक बहुत मोटा अनुमान होगा, हालांकि चीजें धीमी हो सकती हैं यदि कैश / मेमोरी / जो कुछ भी भरा / भरा हुआ है।

1
धन्यवाद मार्क। कमाल का काम किया। और भी तेजी से फिर डंप से बहाल। ~ ५ घंटे लिया।
ineersa

5

आपका sed विचार एक अच्छा तरीका है, लेकिन त्रुटियों या आपके द्वारा चलाए गए आदेश के बिना, हम आपकी मदद नहीं कर सकते।

हालाँकि, बड़ी तालिकाओं में ऑनलाइन परिवर्तन करने के लिए एक अच्छी तरह से ज्ञात विधि pt-online-schema-change है । इस उपकरण के द्वारा किए गए सरलीकरण की अनदेखी प्रलेखन से की गई है:

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

इस विधि को पूरा होने में थोड़ा समय लग सकता है, लेकिन इस प्रक्रिया के दौरान मूल तालिका पूरी तरह से उपयोग करने योग्य होगी।


मैं आज रात बाद थोक लोडिंग की कोशिश करूंगा। अगर यह काम नहीं करेगा तो इस उपकरण की आवश्यकता होगी। कमांड के रूप में sed का उपयोग करने के बाद त्रुटियां inetifieng द्वारा कुछ प्रतीकों के कारण होती हैं। उदाहरण के लिए 'D\'agostini'त्रुटि का कारण होगा unknown command '\''। लेकिन हमेशा नहीं, 30% मामलों में। अजीब और छोटी बात है। वही हेक्स-ब्लॉब डंप के साथ भी आता है। डेरेक धन्यवाद।
ineersa

4

alter table add column, algorithm=inplace, lock=none तालिका की प्रतिलिपि बनाए बिना और लॉकिंग प्रभाव के बिना MySQL 5.6 तालिका को बदल देगा।

बस इस कल का परीक्षण किया, द्रव्यमान ने 70K पंक्तियों को 280K पंक्ति 7 विभाजन तालिका में, 10K पंक्तियों को प्रत्येक विभाजन में डाला, 5 सेकंड के बीच में अन्य थ्रूपुट की अनुमति देने के लिए सोएं।

बड़े पैमाने पर आवेषण शुरू किया, फिर अलग-अलग सत्रों alterमें MySQL वर्कबेंच में ऊपर दिए गए ऑनलाइन स्टेटमेंट को शुरू किया , alterआवेषण से पहले समाप्त, दो नए कॉलम जोड़े गए, और कोई भी पंक्तियों को परिवर्तित नहीं किया गया जिसका अर्थ है कि MySQL ने किसी भी पंक्तियों की प्रतिलिपि नहीं बनाई है।


1
इस जवाब को अधिक वोट क्यों नहीं मिल रहे हैं ?, क्या यह काम नहीं कर रहा है?
fguillen

1

वर्तमान में, विशाल तालिकाओं को बदलने के लिए सबसे अच्छा विकल्प शायद https://github.com/github/gh-ost है

gh-ost, MySQL के लिए एक ट्रिगलेस ऑनलाइन स्कीमा माइग्रेशन समाधान है। यह परीक्षण योग्य है और ठहराव, गतिशील नियंत्रण / पुनर्संरचना, ऑडिटिंग और कई परिचालन भत्ते प्रदान करता है।

जीएच-ओस्ट माइग्रेशन के दौरान मास्टर पर एक हल्का वर्कलोड पैदा करता है, जो माइग्रेटेड टेबल पर मौजूदा वर्कलोड से डिकोड किया जाता है।

यह मौजूदा समाधानों के साथ वर्षों के अनुभव के आधार पर तैयार किया गया है, और तालिका प्रवास के प्रतिमान को बदलता है।


1

मुझे लगता है कि Mydumper / Myloader इस तरह के संचालन के लिए एक अच्छा उपकरण है: हर दिन बेहतर हो रहा है। आप अपने सीपीयू का उपयोग कर सकते हैं और समानांतर में डेटा लोड कर सकते हैं: http://www.percona.com/blog/2014/03/10/new-mydumper-0-6-1-release-offers-several-performance-and- प्रयोज्य-सुविधाओं /

मैंने घंटों में सैकड़ों गीगाबाइट्स MySQL टेबल लोड करने में कामयाबी हासिल की है।

अब, जब यह एक नया कॉलम जोड़ने की बात आती है, तो मुश्किल है क्योंकि MySQL स्मृति TMPक्षेत्र में पूरी तालिका की प्रतिलिपि बनाता है, ALTER TABLE...हालांकि MySQL 5.6 कहता है कि यह ऑनलाइन स्कीमा परिवर्तन कर सकता है, मैंने उन्हें बिना किसी ताला के साथ बड़े पैमाने पर टेबल के लिए ऑनलाइन करने में कामयाब नहीं किया है। विवाद अभी तक।


-2

मैं सिर्फ एक ही समस्या थी। थोड़ा वर्कअराउंड:

नया Table बनाएँ_ पुराने से चयन करें *;

DELETE FROM new_table से

अन्य नया_समूह ADD COLUMN new_column int (11);

INSERT INTO new_table select *, 0 से old_table

ड्रॉप टेबल old_table; नाम बदलने की तालिका new_table to old_table;


क्यों न केवल एक तालिका बनाने के लिए एक खंड जोड़ दें ताकि यह किसी भी डेटा का चयन न करे? इसके अलावा टेबल को रौंदना अधिक कुशल होगा और फिर डेटा को डिलीट किया जाएगा
जो डब्ल्यू

क्यों हटाना है, कब डालना है बाद में, फिर से। डिफ़ॉल्ट = 0 को ADD COLUMN पर ही परिभाषित कर सकते हैं।
1919 में user195280
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.