2011-06-17 9 views
28

मैं एक नई तालिका के साथ एक InnoDB तालिका को प्रतिस्थापित करने की कोशिश कर रहा हूं, और मैं सभी विदेशी कुंजी संदर्भों को चाहता हूं जो नई तालिका को इंगित करने के लिए पुरानी तालिका को इंगित करते हैं।विदेशी कुंजी संदर्भों को अपडेट किए बिना एक इनो डीबी तालिका का नाम बदलना?

SET foreign_key_checks = 0; 
ALTER TABLE foo RENAME foo_old; 
ALTER TABLE foo_new RENAME foo; 

दुर्भाग्य से, यहां तक ​​कि foreign_key_checks विकलांग के साथ, सभी संदर्भों foo की ओर इशारा करते foo_old को इंगित करने के लिए बदल रहे हैं:

तो मैं इस कोशिश की। अब मैं विदेशी कुंजी संदर्भ अपडेट किए बिना एक मेज नाम बदलने के लिए या तो

  • विदेशी कुंजी संदर्भ पूरे तालिका के पुनर्निर्माण के बिना वापस बदलने के लिए एक तरह से, या
  • एक तरीका के लिए देख रहा हूँ।

मैंने विदेशी कुंजी छोड़ने और उन्हें पुनर्निर्माण करने की कोशिश की, लेकिन चूंकि टेबल बहुत बड़ी हैं, इसमें घंटों लगते हैं। तालिका को बदलने का पूरा बिंदु सीमित डाउनटाइम के साथ एक स्कीमा परिवर्तन करना था।

+0

क्या किसी को पता है कि 2015 में इस मुद्दे पर कोई अपडेट है या नहीं? – Greg

+1

प्रतिस्थापन तालिका समान है, या थोड़ा संशोधित है? उदाहरण के लिए, क्या बदलाव एक बदलाव से किया जा सकता है? यदि ऐसा है, तो आप [pt-online-schema-change -alter-foreign-keys-change] को देख सकते हैं (https://www.percona.com/doc/percona-toolkit/2.1/pt-online- स्कीमा-change.html # cmdoption-pt-ऑनलाइन-स्कीमा परिवर्तन - बदल-विदेशी कुंजी-विधि)। – Dave

उत्तर

6

दुर्भाग्यवश मुझे नहीं लगता कि विदेशी कुंजी को पहले छोड़ दिए बिना आपकी समस्या के आसपास एक रास्ता है और वे उन्हें फिर से बना रहे हैं।

यह मामूली है लेकिन मैंने आपके RENAME आदेशों के साथ कुछ भी देखा। आप उन्हें एक साथ जोड़ सकते हैं और जब तक कि सभी कदम सफल नहीं होते हैं, यह अन्य सभी नामों को वापस ले जाता है। यहां वाक्यविन्यास है:

RENAME TABLE foo TO foo_old, foo_new TO foo; 
+3

मैंने देखा कि फू छोड़ना और फिर इसे पुनर्निर्माण करना विदेशी कुंजी को बरकरार रखता है। चूंकि foo_new मूल रूप से foo की एक प्रति (प्लस एक्स्ट्रा) है (आउटपुट में चयन का उपयोग करके और फिर डेटा डेटा लोड करें), यह एक समाधान हो सकता है। मैं बस टेबल छोड़ दूंगा, इसे फिर से बनाऊंगा और फिर डेटा को लोड कर दूंगा। केवल नामकरण के साथ, मुझे यह तथ्य पसंद है कि जब कुछ गलत हो जाता है तो मेरे पास 'बैकअप' तालिका होती है। और ऐसा लगता है कि एक टेबल छोड़ने से संदर्भों को छूटा जाता है (भले ही वे एक अनजान तालिका को इंगित करते हैं) लेकिन संदर्भ बदलने के बिना तालिका का नाम बदलना संभव नहीं है। –

+0

@ BartvanWissen, क्या यह दृष्टिकोण आपके लिए काम कर रहा है? – Greg

+1

@JamesC, 'RENAME' आपके लिए विदेशी कुंजी बदल देगा। यानी यदि 'बार' संदर्भ 'foo' और आप 'foo' को' foo_old' में बदलते हैं, तो' बार' पर सभी विदेशी कुंजी अब 'foo_old' का संदर्भ लेंगी। चेनिंग नाम एक कथन में बदलता नहीं है। – vhu

8

पुराने प्रश्न, लेकिन निम्नलिखित एक संभावित तरीका है। मूल रूप से तालिकाओं का नाम बदलने के बजाय डेटा को स्थानांतरित करें। आपको निश्चित रूप से यह सुनिश्चित करना होगा कि नया डेटा विदेशी कुंजी नियमों का पालन करे।

SET foreign_key_checks = 0; 
CREATE TABLE IF NOT EXISTS foo_old LIKE foo; 
INSERT INTO foo_old SELECT * FROM foo; 
TRUNCATE foo; 
INSERT INTO foo SELECT * FROM foo_new; 

सुनिश्चित करें कि आप इसे एक प्रश्न के रूप में चलाएं ताकि विदेशी_की_चेक पूरी चीज़ पर लागू हो। उम्मीद है की यह मदद करेगा।

+3

यदि तालिका में लाखों रिकॉर्ड हैं और ऐसा करने का समय कम है तो यह असुरक्षित है। (पहली प्रतिलिपि में दो घंटे सोचें, कुछ समय निकालने के लिए और दो बार प्रतिलिपि बनाने के लिए।) –

7

innodb_file_per_table=ON के साथ MySQL 5.6 पर आपको फ्लाई पर टेबल रिक्त स्थान स्वैप करने की अनुमति देता है। यह पूरी तरह से एसक्यूएल का उपयोग नहीं किया जा सकता क्योंकि फाइल ऑपरेशंस को अलग से करने की आवश्यकता है। इस बिंदु आप नाम सही करने के लिए प्रासंगिक InnoDB फ़ाइलों की प्रतिलिपि की जरूरत पर

SET foreign_key_checks = 0; 
ALTER TABLE foo DISCARD TABLESPACE; 
FLUSH TABLES foo_new FOR EXPORT; 

: सबसे पहले foo_new तालिका कॉपी करने के लिए तैयार करने और foo डेटा छोड़ देते हैं। फ़ाइलें आपकी डेटा निर्देशिका में संग्रहीत हैं। डेबियन पर, उदाहरण के लिए, वे डिफ़ॉल्ट रूप से /var/lib/mysql/yourdatabase में हैं और फ़ाइलें foo_new.ibd, foo_new.cfg और foo_new.frm हैं। उन्हें क्रमश: foo.ibd, foo.cfg और foo.frm पर कॉपी करें। उदाहरण के लिए:

$ cp foo_new.ibd foo.ibd 
$ cp foo_new.frm foo.frm 
$ cp foo_new.cfg foo.cfg 

ध्यान दें कि MySQL की नई फ़ाइलों तक पहुंच है (उदा। उनके पास सही स्वामी, एक्सेस अधिकार हैं)। foo को

UNLOCK TABLES; 
ALTER TABLE foo IMPORT TABLESPACE; 
SET foreign_key_checks = 1; 

यह केवल प्रतियां foo_new: एक बार किया आप फिर से तालिका आयात कर सकते हैं और विदेशी कुंजी सक्षम करें। यदि आपको foo से foo_old कॉपी करने की आवश्यकता है तो चरणों को दोहराएं।

3

InnoDB विदेशी कुंजी में तालिका के आंतरिक सूचक का उपयोग करता है, इसलिए इस तालिका को दिए गए नाम से कोई फर्क नहीं पड़ता (RENAME का उपयोग करके), जब आप SET foreign_key_checks = 0 का उपयोग करते हैं तो बाधाओं को संरक्षित किया जाएगा।

विदेशी कुंजी संदर्भ पूरे तालिका

पुनर्निर्माण innodb_file_per_table=ON का उपयोग करना (@vhu उत्तर देखें) निकटतम हम जा सकते हो जाएगा बिना वापस बदलने के लिए एक तरीका है।

विदेशी कुंजी संदर्भों को अपडेट किए बिना तालिका का नाम बदलने का एक तरीका।

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

यदि आपके पास कुछ बदलाव हैं तो स्विच तक आपके आवेदन में अस्थायी डुप्लिकेट mysql कमांड (हटाएं, अपडेट करें, डालें) से अन्य सभी तालिका सिंक्रनाइज़ करने के लिए और भी तेज़ हो सकता है।

+0

2 डेटाबेस के साथ काम करना चाल है। +1 – fancyPants

0

मुझे इसके चारों ओर एक रास्ता मिला ... आप बस इसे नाम बदलने के बजाय स्रोत तालिका छोड़ दें।

इस उदाहरण के लिए, हम 'mytbl' तालिका को कॉल करेंगे।

  1. स्रोत तालिका की प्रति बनाएं, उदा। 'Mytbl_new'
  2. नई तालिका
  3. में प्रतिलिपि डेटा स्रोत तालिका ड्रॉप 'mytbl'
  4. नाम बदलने 'mytbl'

केवल नकारात्मक पक्ष यह है कि आप एक बैकअप नहीं रख सकते हैं है करने के लिए 'mytbl_new' आपकी मूल तालिका का, लेकिन आप इसे हाथ से पहले mysqldump कर सकते हैं। वैकल्पिक रूप से, यदि आप मूल तालिका की क्रियात्मक प्रतिलिपि चाहते हैं तो आप एक अतिरिक्त तालिका प्रतिलिपि बना सकते हैं।

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