2011-08-21 10 views
5

मान लीजिए कि मैं 1000 अनुरोध एक MySQL तालिका अद्यतन करने के लिए हमारे सर्वर पर प्राप्त की जा रही चला रहे हैं। इस स्थिति में डेडलॉक मुद्दे अनिवार्य रूप से होते हैं। हमने लेन-देन को डेडलॉक्स के लिए अनुशंसित करने के लिए पुनः प्रयास किया है लेकिन वे अभी भी होते हैं।MySQL InnoDB इंजन कतार डीबी ट्रिगर स्वचालित रूप से करता है?

हम नीचे कोई वैकल्पिक समाधान के साथ आ के बारे में सोच रहे हैं।

  1. बनाएं टेबल ए, बी, सी
  2. लिखें अनुरोध क्रमशः सर्वर के लिए आ रहा टेबल डी, अद्यतन करने के लिए एक या बी या सी
  3. में टेबल्स ए, बी और सी पर एक सम्मिलित ट्रिगर बनाएं जो सर्वर पर आने वाले 1000 अनुरोधों को सीधे तालिका डी को उजागर करने के बजाय तालिका डी में डेटा लिख ​​देगा।

इसलिए हमारे प्रश्न जब ऐसा होता है और कई पंक्तियों टेबल ए, बी और सी में लिखा जाता है ए, बी और सी टेबल डी अद्यतन करने के लिए एक ही समय में सक्रिय हो सकता है टेबल्स पर अंतर्निहित ट्रिगर है

क्या MySQL InnoDB इंजन स्वचालित रूप से इन ट्रिगर्स को कतारबद्ध करता है या क्या हमें इसे हमारे कोड में संभालना होगा?

किसी भी मदद की बहुत सराहना की जाती है।

टेबल डी कि है अब इन सभी अनुरोधों द्वारा सीधे अपडेट किया जा रहा है और जहां गतिरोध इस तरह दिखता होता है।

v_user_email varchar(60) NO PRI  
v_device_IMEI varchar(40) NO PRI  
i_adid   int(11)   NO PRI  
i_impressions int(4)   YES 0 
dt_pulllogdttm datetime NO   
c_created_by char(15) NO   
dt_created_on datetime NO   
c_modified_by char(15) YES   
dt_modified_on datetime YES 

PHP जो इस तालिका में पंक्तियों को सम्मिलित/अपडेट करता है, नीचे इस तरह दिखता है। आपको लगता है कि हम अगर यह गतिरोध के कारण विफल हो जाता है लेकिन वहाँ लेनदेन है कि फिर भी असफल रहे हैं और लॉग गतिरोध की वजह से कहते हैं लेन-देन के लिए 3 बार पोस्ट करने का प्रयास देखेंगे।

$updateQuery = "UPDATE tb_ad_pull_log SET i_impressions = (i_impressions + 1), dt_pulllogdttm = SYSDATE(), c_modified_by = '$createdBy', dt_modified_on = SYSDATE() WHERE v_user_email = '$email' AND i_adid = $adId"; 
     if(ExecuteDeadLockQuery($updateQuery, "UPDATE", __LINE__) == 0) // If there is no record for this ad for the user, insert a new record 
     { 
      $insertQuery = "INSERT INTO tb_ad_pull_log VALUES('$email', '$device_IMEI', $adId, 1, SYSDATE(), '$createdBy', SYSDATE(), NULL, NULL)"; 
      ExecuteDeadLockQuery($insertQuery, "INSERT", __LINE__); 
     }  

ExecuteDeadLockQuery समारोह इस तरह दिखता है -

function ExecuteDeadLockQuery($query, $activity, $lineNumber) 
    { 
     global $errorLoggingPath; 
     $maxAttempts = 3; 
     $currentTry = 1; 
     $noOfAffectedRows = -1; 

     while($currentTry <= $maxAttempts) 
     { 
      $currentTry++; 

      mysql_query($query); 

      if(mysql_errno() <> 0) // If error occured 
      { 
       continue; 
      } 
      else 
      { 
       $noOfAffectedRows = mysql_affected_rows(); 
       break; 
      }   
     } 

     if($noOfAffectedRows == -1) // Query never executed successfully 
     { 
      LogError($activity . " failed in tb_ad_pull_log: " . mysql_error(), __FILE__, $lineNumber , $errorLoggingPath); 
     } 

     return $noOfAffectedRows; 
    } 

वहाँ एक क्लीनर तरीका यह गतिरोध से बचने के लिए है? यहां कुछ लॉग हैं जो हमारे पास हैं।

ERROR: 08-21-2011 14:09:57 UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 83 
ERROR: 08-21-2011 14:09:57 INSERT failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 86 
ERROR: 08-21-2011 14:09:57 INSERT failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 86 
ERROR: 08-21-2011 14:09:57 UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 83 
ERROR: 08-21-2011 14:09:57 INSERT failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 86 
ERROR: 08-21-2011 14:09:57 UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 83 
ERROR: 08-21-2011 14:09:59 UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 83 
ERROR: 08-21-2011 14:09:59 UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 83 
ERROR: 08-21-2011 14:10:01 UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 83 
ERROR: 08-21-2011 14:10:01 INSERT failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction LINE 86 

लाइन 83 PHP में अद्यतन विवरण है और 86 INSERT है। कृपया ध्यान रखें कि इस डेटा को प्रति सेकंड 5-8 लेनदेन की दर से इस तालिका में लिखा जा सकता है।

अतिरिक्त जानकारी

हर सम्मिलित करें और टेबल डी में अद्यतन एक ट्रिगर निष्पादित करता है कि अद्यतन टेबल एक्स और टेबल वाई इस के लिए तालिका डी बंद कर दिया रहने के लिए और इसलिए आने वाले अनुरोधों को एक हो जाता है एक कारण है के साथ गतिरोध?

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

स्निपेट है।

CREATE DEFINER=CURRENT_USER TRIGGER tuadmin.t_update_CPM_updateBalance 
AFTER UPDATE 
ON tb_ad_pull_log 
FOR EACH ROW 
BEGIN 

    DECLARE `cpm_value` decimal(10,4); 
    DECLARE `clientid` int(4); 

    /* Execute the below block if the requested ad is not the default ad */ 
    IF NEW.i_adid <> 1 THEN 

     SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; 
      //do updates to TABLE X and Y logic 
END 

यह वह जगह है जहाँ मैं समझ में नहीं आता क्यों इन ट्रिगर्स टेबल डी पर एक ताला पकड़ होगा और न जाने किसी भी सम्मिलित/अपडेट समवर्ती होता है।

क्या हम सभी समस्याओं से बचेंगे यदि हम ट्रिगर छोड़ देते हैं और केवल काम करने के लिए PHP से एसपी को कॉल करते हैं?

+0

क्या अपने लेनदेन की तरह लग रहे बनाने के लिए करना चाहते हैं? डेडलॉक करने के लिए, आपके पास 1 से अधिक लेन-देन होना चाहिए, जो पहले से ही एक पंक्ति अपडेट कर चुका है और दूसरी पंक्ति को अपडेट करने का प्रयास करता है, लेकिन उस पंक्ति को दूसरे लेनदेन द्वारा अपडेट किया गया था। सिमनल आवेषण, साथ ही साथ केवल 1 पंक्ति पर अपडेट, डेडलॉक का कारण नहीं बनेंगे। शायद आपको अपने अपडेट प्रश्नों को सीमित/सीमित करने की आवश्यकता है? –

+0

@Darhazer लेनदेन के विवरण के साथ प्रश्न अद्यतन किया। आपका सहयोग सराहनीय है। – Aakash

+0

क्या आपके पास v_user_email/i_adid पर अनुक्रमणिका है। यदि नहीं, तो है कि एक गतिरोध पैदा कर रहा है, अद्यतन क्वेरी सभी रिकॉर्ड को स्कैन करने के लिए है कारण –

उत्तर

0

इस मामले में MYSQL डीबीए का उपयोग "प्रतिकृति" नामक एक विशेषता है, जो भार को संतुलित करने के लिए आवश्यक सर्वरों में एक सर्वर को विभाजित करता है। आप एक शक्तिशाली हार्डवेयर का उपयोग करके ऐसा कर सकते हैं, वर्चुअलबॉक्स, वर्चुअल पीसी, या आपके वर्चुअलाइजेशन स्वाद के साथ वर्चुअल उपकरणों के अंदर चल रहे 2 या अधिक वर्चुअल सर्वरों में विभाजित, MYSQL प्रतिकृति सुविधा सक्षम है।

आप लिखने के लिए एक सर्वर को लिख सकते हैं (इस मामले में आपके अपडेट) और डेटा को पढ़ने वाले प्रश्नों के लिए अन्य सर्वर। MYSQL प्रतिकृति दस्तावेज देखें here

1

ठीक है, तो आप एक ही टेबल और कुछ ट्रिगर्स का उपयोग कर रहे हैं?

और आपके पास प्रति सेकंड केवल बहुत कम लेन-देन हैं?

और आपके पास अजीब लॉकिंग समस्याएं हैं?

उपयोग PostgreSQL, मैं निम्न में से काफी यकीन है: एक) यह उन समस्याओं नहीं होगा ख) यदि यह उन्हें है, तो आपको

99.99% है कुछ ही समय में समुदाय के समर्थन होगा संभावना है कि आपकी समस्या VERY_SLOW_TRIGGERS के कारण होती है, मेरा मतलब है कि पूरी तरह से बहुत धीमी गति से, क्योंकि केवल 8 प्रति सेकेंड 125 एमएमएस का लेनदेन चलने का समय है जो विशाल है।

ताला के लिए कारण स्पष्ट है, आप मेज पर एक ट्रिगर बुला रहे हैं डी

-> call modification on table D 
-> before mod trigger 
-> modification 
-> after mod trigger 
-> modification complete 

अर्थात आपके ट्रिगर में जो कुछ भी होता है वह तालिका डी पर लेनदेन का हिस्सा होता है, और इस प्रकार इसे समाप्त होने तक लॉक रखेगा।

आप या तो:

क) ताला कम पंक्तियों

ख) कम समय ताला -> वहाँ

ग से दूसरे टेबल, प्रक्रिया async में डालने) एक RDBMS कि चलाता ठीक से समर्थन करता है, का उपयोग करें

संतुलन विकल्प हैमर-बनाम-फ्लाई विकल्प है, ऐसा कोई कारण नहीं है कि आपको कम टीपीएस गिनती के लिए एक से अधिक सर्वर की आवश्यकता होगी।

हालांकि, आपको अपने ट्रिगर के प्रदर्शन की समस्या निवारण करना चाहिए और यह सत्यापित करना चाहिए कि आप कहीं भी I/O भीड़ में नहीं चल रहे हैं (आमतौर पर जो अनावश्यक रूप से धीमी गति से संसाधनों का उपयोग करने के लिए धीमा होता है)।

ठीक है, यहाँ एक और विकल्प है:

अनलॉक तालिकाएं स्पष्ट रूप से वर्तमान सत्र द्वारा आयोजित किसी भी तालिका ताले विज्ञप्ति।

यदि आपकी पिछली क्रिया कि अद्यतन है/सम्मिलित और यदि आपके ट्रिगर ऐसा न करने पर या तो असंभव या नहीं एक मुद्दा है

तो फिर आप अपने ट्रिगर की शुरुआत में इस इस्तेमाल कर सकते हैं, सभी ताले को छोड़ता है और के लिए ही पूछ गैर-लॉकिंग लगातार पढ़ा।

1

mysql अवरुद्ध और सिंक्रनाइज़ेड ऑप्शन में अपडेट और डालें, मान लीजिए कि आपके पास टेबल डी अपडेट करने के लिए 2 ट्रिगर से 2 अनुरोध आ रहे हैं, जब 1 तालिका अपडेट कर रहा है डी दूसरे को कतार पर इंतजार किया गया है। चयन करें कि कोई सिंक्रनाइज़ेड ब्लॉक 2 नहीं है धागा एक ही समय में अनुरोध कर सकते हैं आप यह संभव ही समय लेनदेन आप प्रतिकृति बनाने चाहिए

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