"INSERT IGNORE" बनाम "INSERT ... ऑन डुप्लीकेट प्रमुख अद्यतन"


833

INSERTकई पंक्तियों के साथ एक कथन निष्पादित करते समय , मैं डुप्लिकेट प्रविष्टियों को छोड़ना चाहता हूं जो अन्यथा विफलता का कारण बनेंगे। कुछ शोधों के बाद, मेरे विकल्प या तो उपयोग में आते हैं:

  • ON DUPLICATE KEY UPDATE जिसका अर्थ है कि किसी भी कीमत पर एक अनावश्यक अद्यतन, या
  • INSERT IGNORE जिसका अर्थ है अघोषित रूप से फिसलने के लिए अन्य प्रकार की विफलता के लिए निमंत्रण।

क्या मैं इन धारणाओं में सही हूँ? बस उन पंक्तियों को छोड़ देने का सबसे अच्छा तरीका क्या है जो डुप्लिकेट का कारण बन सकती हैं और बस अन्य पंक्तियों को जारी रख सकती हैं?

जवाबों:


990

मैं उपयोग करने की सलाह दूंगा INSERT...ON DUPLICATE KEY UPDATE

यदि आप उपयोग करते हैं INSERT IGNORE, तो पंक्ति को वास्तव में डाला नहीं जाएगा यदि यह एक डुप्लिकेट कुंजी के परिणामस्वरूप होता है। लेकिन कथन में कोई त्रुटि नहीं होगी। इसके बजाय एक चेतावनी उत्पन्न करता है। इन मामलों में शामिल हैं:

  • डुप्लिकेट कुंजी को कॉलम PRIMARY KEYया UNIQUEबाधाओं के साथ सम्मिलित करना ।
  • एक NOT NULLबाधा के साथ एक कॉलम में एक NULLting।
  • एक विभाजन तालिका में एक पंक्ति सम्मिलित करना, लेकिन आपके द्वारा डाले गए मान विभाजन में मैप नहीं होते हैं।

यदि आप उपयोग करते हैं REPLACE, तो MySQL वास्तव में आंतरिक रूप से DELETEअनुसरण करता है INSERT, जिसके कुछ अप्रत्याशित दुष्प्रभाव हैं:

  • एक नई ऑटो-इंक्रीमेंट आईडी आवंटित की गई है।
  • विदेशी कुंजियों के साथ आश्रित पंक्तियों को हटाया जा सकता है (यदि आप विदेशी कुंजी का उपयोग करते हैं) या तो रोकें REPLACE
  • आग लगाने वाले ट्रिगर को DELETEअनावश्यक रूप से निष्पादित किया जाता है।
  • साइड इफेक्ट्स को प्रतिकृतियों में भी प्रचारित किया जाता है।

सुधार: दोनों REPLACEऔर INSERT...ON DUPLICATE KEY UPDATEगैर मानक, MySQL के मालिकाना आविष्कार विशिष्ट हैं। ANSI SQL 2003 एक MERGEबयान को परिभाषित करता है जो समान आवश्यकता (और अधिक) को हल कर सकता है, लेकिन MySQL MERGEकथन का समर्थन नहीं करता है ।


एक उपयोगकर्ता ने इस पोस्ट को संपादित करने का प्रयास किया (संपादन मॉडरेटर्स द्वारा अस्वीकार कर दिया गया था)। संपादन ने एक दावा जोड़ने की कोशिश की जिसके INSERT...ON DUPLICATE KEY UPDATEकारण एक नई ऑटो-इंक्रीमेंट आईडी आवंटित की गई है। यह सही है कि नई आईडी जनरेट की गई है , लेकिन इसे परिवर्तित पंक्ति में उपयोग नहीं किया गया है।

नीचे प्रदर्शन देखें, Percona सर्वर 5.5.28 के साथ परीक्षण किया गया। कॉन्फ़िगरेशन चर innodb_autoinc_lock_mode=1(डिफ़ॉल्ट):

mysql> create table foo (id serial primary key, u int, unique key (u));
mysql> insert into foo (u) values (10);
mysql> select * from foo;
+----+------+
| id | u    |
+----+------+
|  1 |   10 |
+----+------+

mysql> show create table foo\G
CREATE TABLE `foo` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `u` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `u` (`u`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1

mysql> insert into foo (u) values (10) on duplicate key update u = 20;
mysql> select * from foo;
+----+------+
| id | u    |
+----+------+
|  1 |   20 |
+----+------+

mysql> show create table foo\G
CREATE TABLE `foo` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `u` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `u` (`u`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1

उपरोक्त दर्शाता है कि IODKU स्टेटमेंट डुप्लिकेट का पता लगाता है, और के मूल्य को बदलने के लिए अद्यतन को आमंत्रित करता है u। नोट AUTO_INCREMENT=3इंगित करता है कि एक आईडी उत्पन्न हुई थी, लेकिन पंक्ति में इसका उपयोग नहीं किया गया था।

जबकि REPLACEमूल पंक्ति को हटाता है और एक नई पंक्ति सम्मिलित करता है, जिससे एक नई ऑटो-वृद्धि आईडी का निर्माण और भंडारण होता है:

mysql> select * from foo;
+----+------+
| id | u    |
+----+------+
|  1 |   20 |
+----+------+
mysql> replace into foo (u) values (20);
mysql> select * from foo;
+----+------+
| id | u    |
+----+------+
|  3 |   20 |
+----+------+

3
मुझे आश्चर्य है कि अगर mysql डेवलपमेंट टीम का ANSI SQL 2003 से MERGE को अपनाने का कोई इरादा है?
लोनी बेस्ट

1
@ लॉनीबेस्ट: एमईआरजीई को लागू करने का फीचर अनुरोध 2005 में किया गया था, लेकिन जहां तक ​​मुझे पता है, कोई प्रगति या योजना नहीं है। Bugs.mysql.com/bug.php?id=9018
Bill Karwin

2
ओह, मैं यह जोड़ सकता हूं कि यह अमान्य प्रकार के बेमेल के लिए चेतावनियां (त्रुटियां नहीं) उत्पन्न करता है, लेकिन यह प्राथमिक प्राथमिक कुंजी की नकल के लिए चेतावनी उत्पन्न नहीं करता है।
फेब्रीसियो मैटे

11
मैं बस एक टेबल को देख रहा हूं जिसे बहुत सारे INSERT ... ON DUPLICATE KEY UPDATE ...बयानों से आबाद किया गया है । बहुत सारे डेटा डुप्लिकेट हैं, और इसके परिणामस्वरूप दो पंक्तियों के बीच एआई पीके का एक उदाहरण 17,029,941 से बढ़कर 46,271,740 हो गया है। हर बार एक नई AI की पीढ़ी का मतलब है कि आपकी सीमा बहुत जल्दी भर सकती है और आपको सफाई करने की आवश्यकता है। यह तालिका केवल दो सप्ताह पुरानी है!
अभियंता

4
@AntTheKnee, आह, बिग डेटा के समय में काम करने की चुनौतियाँ।
बिल कार्विन

174

यदि आप यह देखना चाहते हैं कि यह सब क्या है, तो यहां हर चीज का झटका है:

CREATE TABLE `users_partners` (
  `uid` int(11) NOT NULL DEFAULT '0',
  `pid` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`uid`,`pid`),
  KEY `partner_user` (`pid`,`uid`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

प्राथमिक कुंजी इस त्वरित संदर्भ तालिका के दोनों स्तंभों पर आधारित है। प्राथमिक कुंजी के लिए अद्वितीय मानों की आवश्यकता होती है।

चलो शुरू करें:

INSERT INTO users_partners (uid,pid) VALUES (1,1);
...1 row(s) affected

INSERT INTO users_partners (uid,pid) VALUES (1,1);
...Error Code : 1062
...Duplicate entry '1-1' for key 'PRIMARY'

INSERT IGNORE INTO users_partners (uid,pid) VALUES (1,1);
...0 row(s) affected

INSERT INTO users_partners (uid,pid) VALUES (1,1) ON DUPLICATE KEY UPDATE uid=uid
...0 row(s) affected

ध्यान दें, ऊपर दिए गए कॉलम को स्वयं के बराबर सेट करके बहुत अधिक अतिरिक्त कार्य सहेजे गए हैं, वास्तव में किसी भी अपडेट की आवश्यकता नहीं है

REPLACE INTO users_partners (uid,pid) VALUES (1,1)
...2 row(s) affected

और अब कुछ एकाधिक पंक्ति परीक्षण:

INSERT INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4)
...Error Code : 1062
...Duplicate entry '1-1' for key 'PRIMARY'

INSERT IGNORE INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4)
...3 row(s) affected

कंसोल में कोई अन्य संदेश उत्पन्न नहीं हुए थे, और अब इसमें तालिका डेटा में 4 मान हैं। मैंने (1,1) को छोड़कर सब कुछ डिलीट कर दिया ताकि मैं उसी प्लेइंग फील्ड से टेस्ट कर सकूं

INSERT INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4) ON DUPLICATE KEY UPDATE uid=uid
...3 row(s) affected

REPLACE INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4)
...5 row(s) affected

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


मैंने डुप्लिकेट कुंजी पर दोनों को चलाया और बदल दिया। मेरी तालिका ~ 120K पंक्तियों के साथ समाप्त हो गई, जिसमें मेरी पंक्तियों का लगभग 30% डुप्लिकेट था। डुप्लिकेट कुंजी पर 102 सेकंड में भाग गया और 105 सेकंड में भाग गया। मेरे मामले के लिए, मैं डुप्लिकेट कुंजी पर चिपका रहा हूं।
crunkchitis

1
मारियाडीबी 10 के साथ उपरोक्त परीक्षण किया गया और दौड़ते समय चेतावनी मिली INSERT IGNORE INTO users_partners (uid,pid) VALUES (1,1),(1,2),(1,3),(1,4)
फ्लोरिस

क्या MySQL संस्करण आप इस सब के लिए इस्तेमाल किया?
रादु मुरझिया

41

जोड़ने के लिए कुछ महत्वपूर्ण: जब INSERT IGNORE का उपयोग कर रहे हैं और आपके पास महत्वपूर्ण उल्लंघन हैं, तो MySQL चेतावनी नहीं बढ़ाता है!

यदि आप एक बार में 100 रिकॉर्ड डालने की कोशिश करते हैं, तो एक दोषपूर्ण के साथ, आपको इंटरेक्टिव मोड में मिलेगा:

Query OK, 99 rows affected (0.04 sec)

Records: 100 Duplicates: 1 Warnings: 0

जैसा कि आप देख रहे हैं: कोई चेतावनी नहीं! इस व्यवहार को आधिकारिक तौर पर मैसिकल डॉक्यूमेंटेशन में भी गलत तरीके से वर्णित किया गया है।

यदि आपकी स्क्रिप्ट को सूचित करने की आवश्यकता है, अगर कुछ रिकॉर्ड नहीं जोड़े गए हैं (कुंजी उल्लंघनों के कारण) आपको mysql_info () को कॉल करना होगा और इसे "डुप्लिकेट" मान के लिए पार्स करना होगा।


6
यदि आप PHP का उपयोग कर रहे हैं, तो आपको यह जानने के लिए उपयोग mysqli_affected_rows()करना होगा कि क्या INSERTवास्तव में हुआ है।
अमल मुरली

दोनों MySQL 5.5 और MariaDB 10 के साथ मैं ऐसा कोई त्रुटि मिलती है Cannot add or update a child row: a foreign key constraint fails और यदि कोई भी पंक्ति (यहां तक कि वैध वाले) जोड़ रहे हैं।
फ्लोरिस

2
@ फ़्लोरिस यह त्रुटि एक विदेशी कुंजी बाधा के कारण है न कि डुप्लिकेट कुंजी के कारण । मैं MySQL 5.5.28 का उपयोग कर रहा हूं। उपयोग करते समय INSERT IGNORE, डुप्लिकेट कुंजियों को बिना किसी त्रुटि या चेतावनी के अनदेखा किया जाता है।
टॉक्सालॉट

20

मैं नियमित रूप से उपयोग करता हूं INSERT IGNORE, और यह बिल्कुल वैसा ही व्यवहार करता है जैसा आप चाहते हैं। जब तक आप जानते हैं कि जो पंक्तियाँ सूचकांक संघर्ष का कारण बनेंगी, उन्हें सम्मिलित नहीं किया जाएगा और आप अपने कार्यक्रम की योजना उसी के अनुसार बनाते हैं, तो इससे कोई परेशानी नहीं होनी चाहिए।


4
मुझे चिंता है कि मैं नकल के अलावा अन्य त्रुटियों को नजरअंदाज कर दूंगा। क्या यह सही है या INSERT IGNORE केवल दोहराव की विफलता को अनदेखा करता है? धन्यवाद!
थॉमस जी हेनरी

2
यह किसी भी त्रुटि को चेतावनी में बदल देता है। मेरे उत्तर में ऐसे मामलों की एक सूची देखें।
बिल कार्विन

कि एक शर्म की बात है; काश, यह केवल डुप्लिकेट विफलताओं को अनदेखा करता।
लोनी बेस्ट

मुख्य उल्लंघन त्रुटियों का कारण बनते हैं ! मेरी टिप्पणी @Jens 'के उत्तर पर देखें।
फ्लोरिस

1
@ स्पेसर, यह इस बात पर निर्भर करता है कि आपका आवेदन चेतावनियों के लिए जाँच करता है या नहीं। या अगर यह चेतावनी के लिए जाँच कर सकते हैं । उदाहरण के लिए, अधिकांश ORM पैकेज आपको अवसर नहीं देते हैं। कुछ कनेक्टर (उदाहरण के लिए JDBC) भी आपको MySQL API से अलग करते हैं ताकि आपको चेतावनियों को जाँचने का अवसर न मिले।
बिल करविन

18

मुझे पता है कि यह पुराना है, लेकिन मैं इस नोट को किसी और (जैसे मेरे) इस पेज पर आने पर INSERT..IGNORE पर जानकारी खोजने का प्रयास करते हुए जोड़ दूंगा।

जैसा कि ऊपर उल्लेख किया गया है, यदि आप INSERT..IGNORE का उपयोग करते हैं, तो INSERT स्टेटमेंट निष्पादित करते समय होने वाली त्रुटियों को चेतावनी के रूप में माना जाता है।

एक बात जिसका स्पष्ट रूप से उल्लेख नहीं किया गया है वह यह है कि INSERT..IGNORE अमान्य मानों को सम्‍मिलित किए जाने पर निकटतम मानों में समायोजित हो जाएगा (जबकि अमान्य मान क्वेरी को निरस्त करने का कारण बनेंगे यदि IGNORE कीवर्ड का उपयोग नहीं किया गया था)।


6
मुझे वास्तव में यकीन नहीं है कि आपके "अमान्य मूल्यों" से क्या मतलब है और क्या सही है? क्या आप एक उदाहरण या आगे की व्याख्या प्रदान कर सकते हैं?
मार्केज

4
इसका अर्थ है कि यदि आप "INSERT IGNORE" का उपयोग करते समय किसी गलत डेटा प्रकार को किसी फ़ील्ड में सम्मिलित करते हैं, तो डेटा को फ़ील्ड के डेटा प्रकार से मिलान करने के लिए संशोधित किया जाएगा और एक संभावित अमान्य मान डाला जाएगा, फिर क्वेरी जारी रहेगी। केवल "INSERT" के साथ, गलत डेटा प्रकार के बारे में एक त्रुटि उठाई जाएगी और क्वेरी को निरस्त कर दिया जाएगा। यह एक वर्कशॉप या टेक्स्ट फ़ील्ड में डाली गई संख्या के साथ ठीक हो सकता है, लेकिन संख्यात्मक डेटा प्रकार के साथ फ़ील्ड में टेक्स्ट स्ट्रिंग डालने से डेटा खराब हो जाएगा।
12 कोडवर्ड

2
@Marenz एक और उदाहरण: यदि आपकी तालिका में एक अशक्त स्तंभ है और आपके "INSERT IGNORE" क्वेरी में उस स्तंभ के लिए कोई मान निर्दिष्ट नहीं है, तो पंक्ति को उस स्तंभ में शून्य मान के साथ डाला जाएगा, चाहे वह सख्त sql_mode सक्षम हो या नहीं ।
शैनन

अमान्य मूल्यों के बारे में अच्छी बात! यह धागा "INSERT IGNORE" के बारे में जानने के लिए बहुत अच्छा है, मैं अपने 5 सेंट भी छोड़ दूँगा: medium.com/legacy-systems-diary/… "INSERT IGORE" का उपयोग करते समय आपको कितनी सावधानी बरतनी चाहिए, इस उदाहरण के साथ। बयान।
0x49D1

8

DUPLICATE KEY UPDATE वास्तव में मानक में नहीं है । यह REPLACE के रूप में मानक के बारे में है। SQL MERGE देखें ।

अनिवार्य रूप से दोनों कमांड मानक कमांड के वैकल्पिक-वाक्यविन्यास संस्करण हैं।


1
प्रतिस्थापित एक डिलीट और इंसर्ट करता है, जबकि ऑनडुप्लिकेट कुंजी अपडेट मौजूदा पंक्ति को अपडेट करता है। कुछ अंतर हैं: ऑटो वेतन वृद्धि आईडी, पंक्ति की स्थिति, ट्रिगर का एक गुच्छा
ahnbizcad

8

Replaceएक विकल्प की तरह लगता है। या आप के साथ जाँच कर सकते हैं

IF NOT EXISTS(QUERY) Then INSERT

यह सम्मिलित करेगा या हटाएगा। मैं IF NOT EXISTSपहले जांच के लिए जाता हूं ।


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

6
NTuplip - यह समाधान अभी भी समवर्ती लेनदेन द्वारा आवेषण से दौड़ की स्थिति के लिए खुला है।
क्रिस केएल

REPLACEकिसी भी PRIMARY या UNIQUEकुंजी के मिलान के साथ तालिका में सभी पंक्तियों को हटा देता है , फिर INSERTs । यह संभावित रूप से बहुत अधिक काम है तो IODKU।
रिक जेम्स

4

INSERT IGNORE का संभावित खतरा। यदि आप VARCHAR मान को लंबे समय तक सम्मिलित करने का प्रयास कर रहे हैं, तो कॉलम के साथ परिभाषित किया गया था - मान को छोटा किया जाएगा और ईवीएन डाला जाएगा यदि सख्त मोड सक्षम है।


3

यदि आपके क्वेरी सेट के अंत में insert ignoreएक SHOW WARNINGS;स्टेटमेंट का उपयोग करते हुए सभी चेतावनियों के साथ एक तालिका दिखाई देगी, जिसमें आईडी डुप्लिकेट थे।


SHOW WARNINGS;केवल नवीनतम क्वेरी को प्रभावित करता है। कोई पिछला कथन संचित नहीं है, यदि आपके पास एक से अधिक कथन हैं।
कवु

2

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

वाक्य - विन्यास:

insert into table1 set column1 = a, column2 = b on duplicate update column2 = c;

अब यहाँ, यह सम्मिलित विवरण अलग दिख सकता है जो आपने पहले देखा है। यह सम्मिलित विवरण तालिका 1 और कॉलम 2 में क्रमशः ए और बी के मूल्य के साथ तालिका 1 में एक पंक्ति डालने की कोशिश कर रहा है।

आइए इस कथन को गहराई से समझते हैं:

उदाहरण के लिए: यहां कॉलम 1 को टेबल 1 में प्राथमिक कुंजी के रूप में परिभाषित किया गया है।

अब अगर टेबल 1 में स्तंभ 1 में "a" मान वाली कोई पंक्ति नहीं है। तो यह कथन तालिका 1 में एक पंक्ति सम्मिलित करेगा।

अब अगर तालिका 1 में स्तंभ 2 में "a" मान वाली एक पंक्ति है। तो यह कथन पंक्ति के कॉलम 2 मान को "c" से अपडेट करेगा जहां कॉलम 1 मान "a" है।

इसलिए यदि आप एक नई पंक्ति सम्मिलित करना चाहते हैं अन्यथा प्राथमिक कुंजी या अनन्य अनुक्रमणिका के विरोध में उस पंक्ति को अपडेट करें।
इस लिंक पर और पढ़ें


0

INSERT...ON DUPLICATE KEY UPDATE अप्रत्याशित अपवाद प्रबंधन को रोकने के लिए पसंद किया जाता है।

यह समाधान तब काम करता है जब आपके पास ** 1 अद्वितीय बाधा ** होती है

मेरे मामले में मुझे पता है कि col1और col2एक अद्वितीय समग्र सूचकांक बनाते हैं।

यह त्रुटि का ट्रैक रखता है, लेकिन डुप्लिकेट पर अपवाद नहीं फेंकता है। प्रदर्शन के संबंध में, उसी मान से अपडेट कुशल है क्योंकि MySQL ने इसे नोटिस किया है और इसे अपडेट नहीं करता है

INSERT INTO table
  (col1, col2, col3, col4)
VALUES
  (?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
    col1 = VALUES(col1),
    col2 = VALUES(col2)

इस दृष्टिकोण का उपयोग करने का विचार phpdelusions.net/pdo पर टिप्पणियों से आया है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.