जब कोई वेबसाइट या वेब ऐप्लिकेशन शुरू होता है, तो उसका डेटाबेस छोटा होता है और हर SQL क्वेरी मिलीसेकंड्स में रन हो जाती है। लेकिन जैसे-जैसे यूज़र्स बढ़ते हैं और टेबल्स में लाखों रिकॉर्ड्स जमा होने लगते हैं, सर्वर का CPU यूसेज 100% तक पहुँच जाता है और यूज़र्स को स्लो लोडिंग का सामना करना पड़ता है।
अधिकतर मामलों में समस्या सर्वर हार्डवेयर की नहीं, बल्कि खराब तरीके से लिखी गई SQL Queries और इंडेक्सिंग (Indexing) की कमी की होती है। इस गाइड में हम प्रैक्टिकल उदाहरण के साथ सीखेंगे कि MySQL में EXPLAIN कमांड का इस्तेमाल करके बॉटलनेक्स कैसे पहचानें और सही इंडेक्सिंग से क्वेरी स्पीड को 10x से 100x तक कैसे बढ़ाएं।
Slow Query की पहचान कैसे करें?
किसी भी क्वेरी को ऑप्टिमाइज़ करने से पहले यह जानना ज़रूरी है कि कौन सी क्वेरी सर्वर पर सबसे ज्यादा समय ले रही है। MySQL में इसके लिए Slow Query Log फीचर इनबिल्ट होता है।
आप MySQL कंसोल में निम्नलिखित कमांड रन करके इसे एक्टिवेट कर सकते हैं:
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow-queries.log';
इसका मतलब है कि जो भी क्वेरी 1 सेकंड से अधिक समय लेगी, वह लॉग फ़ाइल में रिकॉर्ड हो जाएगी। इस लॉग से आपको वह SQL स्टेटमेंट मिल जाएगा जिसे ऑप्टिमाइज़ करने की ज़रूरत है।
स्टेप 1: EXPLAIN Command से Query Execution Plan समझना
मान लीजिए हमारे पास एक ई-कॉमर्स डेटाबेस है जिसमें orders नाम की टेबल है और उसमें 5 लाख रिकॉर्ड्स हैं। हम किसी खास कस्टमर के पेंडिंग ऑर्डर्स खोजना चाहते हैं:
SELECT order_id, order_date, total_amount
FROM orders
WHERE customer_id = 45210 AND status = 'PENDING';
यह जानने के लिए कि डेटाबेस इंजन बैकएंड में इस क्वेरी को कैसे प्रोसेस कर रहा है, क्वेरी के आगे EXPLAIN जोड़ें:
EXPLAIN SELECT order_id, order_date, total_amount
FROM orders
WHERE customer_id = 45210 AND status = 'PENDING';
EXPLAIN आउटपुट के 4 महत्वपूर्ण कॉलम्स:
- type: यह बताता है कि डेटा कैसे ढूंढा गया। अगर यहाँ
ALLलिखा है, तो इसका मतलब है Full Table Scan—डेटाबेस ने टेबल की हर एक पंक्ति को स्कैन किया, जो परफॉरमेंस का दुश्मन है। आदर्श रूप से यहाँref,eq_refयाrangeहोना चाहिए। - possible_keys: कौन-कौन से इंडेक्स इस क्वेरी के लिए काम आ सकते थे।
- key: MySQL ने असल में किस इंडेक्स का इस्तेमाल किया। अगर यहाँ
NULLहै, तो कोई इंडेक्स काम नहीं आया। - rows: रिजल्ट निकालने के लिए इंजन को लगभग कितनी पंक्तियां पढ़नी पड़ीं। अगर 1 रिकॉर्ड के लिए 5,00,000 पंक्तियां स्कैन हो रही हैं, तो तुरंत सुधार की ज़रूरत है।
स्टेप 2: सही B-Tree Index तैयार करना
हमारी टेबल में WHERE क्लॉज के अंदर दो कॉलम्स इस्तेमाल हुए हैं: customer_id और status। अगर हम केवल customer_id पर इंडेक्स बनाएंगे, तो भी डेटाबेस को स्टेटस फ़िल्टर करने के लिए अतिरिक्त डिस्क I/O करना पड़ेगा।
यहाँ सबसे सही समाधान है Composite Index (मल्टी-कॉलम इंडेक्स) बनाना:
CREATE INDEX idx_orders_customer_status
ON orders (customer_id, status);
इंडेक्स बनने के बाद जब आप दोबारा वही EXPLAIN कमांड रन करेंगे, तो आप देखेंगे:
typeबदलकरrefहो गया है।keyकॉलम मेंidx_orders_customer_statusदिखेगा।rowsकी संख्या 5,00,000 से घटकर मात्र 2 या 3 रह जाएगी।
क्वेरी का एग्जीक्यूशन टाइम 1.8 सेकंड से घटकर मात्र 2 मिलीसेकंड्स पर आ जाएगा।
स्टेप 3: Covering Index से Disk I/O को शून्य करना
जब डेटाबेस इंडेक्स स्कैन करता है, तो उसे बाकी कॉलम्स (जैसे order_date, total_amount) फेच करने के लिए मुख्य डेटा डिस्क (Clustered Index / Table Data) पर जाना पड़ता है। इसे Key Lookup कहते हैं।
यदि कोई क्वेरी बार-बार रन होती है, तो आप Covering Index का उपयोग कर सकते हैं:
CREATE INDEX idx_orders_covering
ON orders (customer_id, status, order_date, total_amount);
अब EXPLAIN के Extra कॉलम में आपको Using index दिखाई देगा। इसका अर्थ है कि इंजन को टेबल के मुख्य डेटा ब्लॉक तक जाने की आवश्यकता ही नहीं पड़ी, सारा डेटा RAM में मौजूद इंडेक्स से ही सर्व हो गया।
Database Indexing में की जाने वाली 5 सामान्य गलतियां
इंडेक्सिंग फायदेमंद है, लेकिन गलत तरीके से इस्तेमाल करने पर यह सर्वर को धीमा भी कर सकती है। इन गलतियों से बचें:
1. हर कॉलम पर इंडेक्स बना देना (Over-indexing)
प्रत्येक इंडेक्स डिस्क स्पेस लेता है। जब भी आप INSERT, UPDATE, या DELETE करते हैं, तो MySQL को हर इंडेक्स ट्री को रीबैलेंस करना पड़ता है। बहुत ज्यादा इंडेक्स होने से डेटा राइट (Write) स्पीड बेहद धीमी हो जाती है।
2. इंडेक्स वाले कॉलम पर फंक्शन्स का उपयोग करना
यदि आप ऐसा लिखते हैं: WHERE YEAR(created_at) = 2024, तो MySQL created_at पर बने इंडेक्स को इग्नोर कर देगा क्योंकि हर रो के लिए फंक्शन रन होना है। इसे ऐसे लिखें:
WHERE created_at >= '2024-01-01 00:00:00'
AND created_at <= '2024-12-31 23:59:59';
3. Leading Wildcard (%keyword) के साथ LIKE इस्तेमाल करना
WHERE name LIKE '%rahul' जैसी क्वेरी इंडेक्स का उपयोग नहीं कर पाती क्योंकि सर्च स्ट्रिंग की शुरुआत अज्ञात है। अगर आपको फुल-टेक्स्ट सर्च की जरूरत है, तो MySQL FULLTEXT Index का उपयोग करें।
4. Composite Index में कॉलम का गलत क्रम (Order)
MySQL Left-to-Right नियम का पालन करता है। यदि इंडेक्स (A, B, C) पर है, तो क्वेरी WHERE B = 5 इस इंडेक्स का पूरा फायदा नहीं उठा पाएगी। इंडेक्स में सबसे पहले वह कॉलम रखें जो सबसे ज्यादा यूनिक डेटा फ़िल्टर करता हो (High Cardinality)।
5. डेटा टाइप्स का बेमेल होना (Implicit Type Conversion)
यदि phone_number कॉलम VARCHAR टाइप का है और आप क्वेरी में नंबर पास कर देते हैं (WHERE phone_number = 9876543210), तो MySQL इंटरनली स्ट्रिंग को नंबर में कन्वर्ट करेगा, जिससे इंडेक्स बाईपास हो जाएगा। हमेशा सही डेटा टाइप पास करें (WHERE phone_number = '9876543210')।
परफॉरमेंस बनाए रखने के लिए प्रैक्टिकल टिप्स
- SELECT * से बचें: हमेशा केवल उन्हीं कॉलम्स के नाम लिखें जिनकी ऐप्लिकेशन को ज़रूरत है। इससे नेटवर्क बैंडविड्थ और मेमोरी दोनों बचती हैं।
- ANALYZE TABLE रन करें: समय-समय पर
ANALYZE TABLE orders;चलाएं ताकि MySQL Query Optimizer के पास इंडेक्स स्टैटिस्टिक्स की सटीक जानकारी रहे। - Unused Indexes को हटाएं:
sys.schema_unused_indexesव्यू से चेक करें कि कौन से इंडेक्स कभी इस्तेमाल नहीं हो रहे और उन्हें ड्रॉप करें।
अक्सर पूछे जाने वाले सवाल (FAQ)
1. B-Tree और Hash Index में क्या अंतर है?
MySQL InnoDB में डिफॉल्ट रूप से B-Tree इंडेक्स का इस्तेमाल होता है, जो रेंज क्वेरी (जैसे >, <, BETWEEN) और सॉर्टिंग (ORDER BY) दोनों में काम करता है। Hash Index केवल डायरेक्ट इक्वैलिटी चेक (=) के लिए बहुत तेज़ होता है, लेकिन रेंज सर्च में काम नहीं करता।
2. क्या 10,000 रिकॉर्ड्स वाली छोटी टेबल पर भी इंडेक्सिंग की आवश्यकता होती है?
अगर टेबल बहुत छोटी है (कुछ सौ या हज़ार पंक्तियां), तो MySQL कई बार इंडेक्स की जगह सीधे टेबल स्कैन करना तेज़ समझता है। फिर भी Foreign Key कॉलम्स और प्राइमरी कीज़ पर इंडेक्स होना हमेशा मानक अभ्यास है।
3. EXPLAIN ANALYZE क्या है और यह सामान्य EXPLAIN से कैसे अलग है?
MySQL 8.0+ में उपलब्ध EXPLAIN ANALYZE क्वेरी का केवल अनुमानित प्लान नहीं दिखाता, बल्कि असल में क्वेरी को रन करके हर स्टेप पर लगा वास्तविक समय और प्रोसेस्ड रोज़ की सटीक संख्या मिलीसेकंड्स में बताता है।

0 Comments
You Can Contact on WhatsApp - 9509503477