अनुक्रमणित स्तंभ के साथ एक बड़ी तालिका पर तालिका बनाएँ


14

मेरे पास VARCHAR (20) कॉलम के साथ एक बड़ी तालिका है, और मुझे इसे VARCHAR (50%) कॉलम बनने के लिए संशोधित करना होगा। आमतौर पर, इस विशेष टेबल पर ALTER TABLE (TINYINT जोड़कर) पूरा करने में लगभग 90-120 मिनट लगते हैं, इसलिए मैं डेटाबेस के उपयोगकर्ताओं को प्रभावित करने से बचने के लिए केवल शनिवार या रविवार की रात को ही ऐसा कर सकता हूं। यदि संभव हो तो मैं इस संशोधन को पहले करना चाहूंगा।

कॉलम को भी अनुक्रमित किया गया है, जो मुझे लगता है कि ALTER TABLE को धीमा कर देगा, क्योंकि इसमें कॉलम की लंबाई को संशोधित करने के बाद इंडेक्स को फिर से बनाना होगा।

वेब ऐप एक MySQL प्रतिकृति वातावरण (26 दास और एक मास्टर) में स्थापित किया गया है। मुझे एक बार कहीं पढ़ने में याद आया कि एक तरीका यह है कि पहले प्रत्येक गुलाम (उपयोगकर्ताओं पर प्रभाव को कम करते हुए) पर पहले टेबल पर प्रदर्शन करें, फिर मास्टर पर ऐसा करें, लेकिन क्या तब दासों को ALTER टेबल कमांड को दोहराने की कोशिश नहीं की जाएगी?

तो मेरा सवाल है: मेरे उपयोगकर्ताओं के लिए न्यूनतम व्यवधान के साथ इस तालिका को संशोधित करने का सबसे अच्छा तरीका क्या है?

संपादित करें: तालिका InnoDB है।


उस छोटे कॉलम को जोड़ने का मतलब वास्तव में एक डिफ़ॉल्ट मान के साथ एक कॉलम जोड़ना है? क्योंकि एक विशाल मेज पर ऐसा करने में लंबा समय लग सकता है ..
मैरियन

जवाबों:


13

यदि आप थोड़े साहसी हैं, तो आप चरणों में उन मामलों को अपने हाथों में ले सकते हैं जिन्हें आप देख सकते हैं। मान लीजिए कि आप जिस तालिका को बदलना चाहते हैं, उसे वर्किंगटेबल कहा जाता है। आप इस तरह चरणों में परिवर्तन कर सकते हैं:

#
#  Script 1
#  Alter table structure of a single column of a large table
#
CREATE TABLE WorkingTableNew LIKE WorkingTable;
ALTER TABLE WorkingTableNew MODIFY BigColumn VARCHAR(50);
INSERT INTO WorkingTableNew SELECT * FROM WorkingTable;
ALTER TABLE WorkingTable RENAME WorkingTableOld;
ALTER TABLE WorkingTableNew RENAME WorkingTable;
DROP TABLE WorkingTableOld;

आप सभी दासों पर यह प्रदर्शन कर सकते हैं। गुरु के बारे में क्या ??? आप इसे दासों की नकल करने से कैसे रोकते हैं। सरल: एसक्यूएल को मास्टर के बाइनरी लॉग में न भेजें। ALTER TABLE सामान करने से पहले बाइनरी लॉगिंग को सत्र में बंद करें:

#
#  Script 2
#  Alter table structure of a single column of a large table
#  while preventing it from replicating to slaves
#
SET SQL_LOG_BIN = 0;
CREATE TABLE WorkingTableNew LIKE WorkingTable;
ALTER TABLE WorkingTableNew MODIFY BigColumn VARCHAR(50);
INSERT INTO WorkingTableNew SELECT SQL_NO_CACHE * FROM WorkingTable;
ALTER TABLE WorkingTable RENAME WorkingTableOld;
ALTER TABLE WorkingTableNew RENAME WorkingTable;
DROP TABLE WorkingTableOld;

लेकिन रुकें !!! इन आदेशों को संसाधित करते समय आने वाले किसी भी नए डेटा के बारे में क्या ??? ऑपरेशन की शुरुआत में तालिका का नाम बदलकर चाल करना चाहिए। उस संदर्भ में नए डेटा दर्ज करने से रोकने के लिए इस कोड को थोड़ा बदल दें:

#
#  Script 3
#  Alter table structure of a single column of a large table
#  while preventing it from replicating to slaves
#  and preventing new data from entering into the old table
#
SET SQL_LOG_BIN = 0;
ALTER TABLE WorkingTable RENAME WorkingTableOld;
CREATE TABLE WorkingTableNew LIKE WorkingTableOld;
ALTER TABLE WorkingTableNew MODIFY BigColumn VARCHAR(50);
INSERT INTO WorkingTableNew SELECT SQL_NO_CACHE * FROM WorkingTableOld;
ALTER TABLE WorkingTableNew RENAME WorkingTable;
DROP TABLE WorkingTableOld;
  • स्क्रिप्ट 1 को किसी भी ऐसे दास पर निष्पादित किया जा सकता है जिसके पास बाइनरी लॉग सक्षम नहीं है
  • स्क्रिप्ट 2 को किसी भी दास पर निष्पादित किया जा सकता है जिसमें बाइनरी लॉग सक्षम हैं
  • स्क्रिप्ट 3 को एक मास्टर या कहीं और निष्पादित किया जा सकता है

कोशिश करो !!!


2
एक समस्या मुझे दिखाई देती है यदि तालिका में एक 'auto_increment' फ़ील्ड है। मैंने एक बुनियादी परीक्षण किया और यह देखकर आश्चर्यचकित रह गया कि सृजन तालिका .. LIKE नई तालिका में Auto_increment मान की प्रतिलिपि नहीं बनाता
Derek Downey

1
@Dest: गुड कैच एंड ग्रेट कमेंट !!!। मेरा मानना ​​है कि आप auto_increment value को information_schema.tables कॉलम AUTO_INCREMENT से प्राप्त कर सकते हैं। यदि तालिका में AUTO_INCREMENT फ़ील्ड नहीं है, तो सूचना_schema.tables में AUTO_INCREMENT कॉलम NULL होगा। अन्यथा, इसमें AUTO_INCREMENT मान आवश्यक होगा। मुझे लगता है कि यह उस गैर-पूर्ण मान को निकालने के लिए स्क्रिप्ट किया जा सकता है और कार्य सारणी को स्वचालित करें AUTO_INCREMENT = <somenumber>; अस्थायी तालिका का नाम बदलने से ठीक पहले वर्कसेट पर वापस जाएं।
रोलैंडमाइसीडीडीबीए

@RolandoMySQLDBA दूसरी चीज़ जो आप कर सकते हैं वह यह है कि आप "शो क्रिएट टेबल वर्किंगटेबल" कथनों को कॉपी करके वर्कटेबल्यूवन बना सकते हैं और स्वतः संख्या के मान को बदलकर इसे एक नंबर से आगे बढ़ा सकते हैं, जो आपके लिए सुरक्षित है, और कॉलम को varcharano में भी बदल सकते हैं (50) ), और उसके बाद दोनों को एक ही नाम में बदल देते हैं "नाम बदलें तालिका WorkingTable to WorkingTableOld, rename Table WorkingTableNew to WorkingTable" आप "इन्सर्ट इन ... फ्रॉम" कमांड
गौतम सोमानी

4

दस्तावेज़ीकरण से मेरा अनुमान यह होगा कि केवल एक पर लंबाई की बाधा बढ़ने से varcharस्तंभ जोड़ने के समान परेशानी नहीं होगी:

कुछ परिचालनों के लिए, इन-प्लेस अलर्ट टेबल संभव है जिसके लिए एक अस्थायी तालिका की आवश्यकता नहीं है:

लेकिन ऐसा लगता है कि इस एसओ प्रश्न पर टिप्पणी में विरोधाभास है ।

संपादित करें

कम से कम 5.0 पर, मुझे लगता है कि मैं पुष्टि कर सकता हूं कि लंबाई बढ़ाने से वास्तव में एक अस्थायी तालिका (या कुछ अन्य समान रूप से महंगा ऑपरेशन) की आवश्यकता होती है:

टेस्टबेड:

create table my_table (id int auto_increment primary key, varchar_val varchar(10));
insert into my_table (varchar_val)
select 'HELLO'
from (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s1,
     (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s2,
     (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s3,
     (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s4,
     (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s5,
     (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s6;

परिणाम:

alter table my_table modify varchar_val varchar(20);
Query OK, 1000000 rows affected (2.91 sec)

alter table my_table add int_val int;
Query OK, 1000000 rows affected (2.86 sec)

चर क्षेत्र आकार को संशोधित करना शामिल है कि आप नए आकार से अधिक नहीं हैं। आकार में वृद्धि के लिए यह जाँच MAY दूर अनुकूलित की जानी चाहिए।
बिलटोर

3

मैंने सोचा, मैं इसका उल्लेख करूंगा ENGINE=INNODB

यदि आपके पास विदेशी मुख्य बाधाएँ हैं, तो आप पुराने तालिका (अब नाम बदलने) की ओर इशारा करते हुए अपने अवरोधों को बदल नहीं सकते हैं और पुनः नाम बदल सकते हैं। आपको बाद में परिवर्तन करना होगा या अवधि के लिए बाधाओं को छोड़ना होगा।


शबंग !!! यह वाकई में सच है। उस स्थिति में, कोई केवल मूल तालिका पर परिवर्तन तालिका के साथ फंस सकता है। बहुत कम से कम, आपको अक्षम होने से पहले गेम खेलना पड़ सकता है, इससे पहले कि ALTER TABLE हो। +1 कि बहुत अच्छी पकड़ के लिए !!!
RolandoMySQLDBA
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.