यहां 10M पंक्तियों के साथ एक MariaDB (10.0.19) बेंचमार्क है (अनुक्रम प्लग इन का उपयोग करके ए> ):
drop table if exists test;
CREATE TABLE `test` (
`id` MEDIUMINT UNSIGNED NOT NULL,
`is_active` TINYINT UNSIGNED NOT NULL,
`deleted_at` TIMESTAMP NULL,
PRIMARY KEY (`id`),
INDEX `is_active` (`is_active`),
INDEX `deleted_at` (`deleted_at`)
) ENGINE=InnoDB
select seq id
, rand(1)<0.5 as is_active
, case when rand(1)<0.5
then null
else '2017-03-18' - interval floor(rand(2)*1000000) second
end as deleted_at
from seq_1_to_10000000;
मेरे द्वारा उपयोग किए जाने वाले समय को मापने के लिए set profiling=1
और show profile
run चलाएं एक क्वेरी निष्पादित करने के बाद। प्रोफाइलिंग परिणाम से मैं Sending data
. का मान लेता हूं चूंकि बाकी सब कुछ एक मिसे से भी कम है।
टिन्यिनट सूचकांक:
SELECT COUNT(*) FROM test WHERE is_active = 1;
रनटाइम:~ 738 मिसे
टाइमस्टैम्प सूचकांक:
SELECT COUNT(*) FROM test WHERE deleted_at is null;
रनटाइम:~ 748 मिसे
सूचकांक आकार:
select database_name, table_name, index_name, stat_value*@@innodb_page_size
from mysql.innodb_index_stats
where database_name = 'tmp'
and table_name = 'test'
and stat_name = 'size'
परिणाम:
database_name | table_name | index_name | stat_value*@@innodb_page_size
-----------------------------------------------------------------------
tmp | test | PRIMARY | 275513344
tmp | test | deleted_at | 170639360
tmp | test | is_active | 97107968
ध्यान दें कि TIMESTAMP (4 बाइट्स) TYNYINT (1 बाइट) से 4 गुना लंबा है, जबकि इंडेक्स का आकार दोगुना बड़ा भी नहीं है। लेकिन सूचकांक का आकार महत्वपूर्ण हो सकता है अगर यह स्मृति में फिट नहीं होता है। तो जब मैं innodb_buffer_pool_size
change बदलता हूं 1G
. से से 50M
. तक मुझे निम्नलिखित नंबर मिलते हैं:
- टिन्यिनट:~ 960 मिसे
- टाइमस्टैम्प:~ 1500 मिसे
अपडेट करें
प्रश्न को और अधिक सीधे संबोधित करने के लिए मैंने डेटा में कुछ बदलाव किए:
- TIMESTAMP के बजाय मैं DATETIME का उपयोग करता हूं
- चूंकि प्रविष्टियां आमतौर पर शायद ही कभी हटाई जाती हैं, मैं
rand(1)<0.99
. का उपयोग करता हूं (1% हटाया गया)rand(1)<0.5
. के बजाय (50% हटाया गया) - टेबल का आकार 10M से 1M पंक्तियों में बदला गया।
SELECT COUNT(*)
SELECT *
. में बदला गया
सूचकांक आकार:
index_name | stat_value*@@innodb_page_size
------------------------------------------
PRIMARY | 25739264
deleted_at | 12075008
is_active | 11026432
चूंकि 99% deleted_at
मान शून्य हैं, इंडेक्स आकार में कोई महत्वपूर्ण अंतर नहीं है, हालांकि एक खाली खाली DATETIME को 8 बाइट्स (MariaDB) की आवश्यकता होती है।
SELECT * FROM test WHERE is_active = 1; -- 782 msec
SELECT * FROM test WHERE deleted_at is null; -- 829 msec
दोनों इंडेक्स को छोड़कर दोनों क्वेरी लगभग 350 मिसे में निष्पादित होती हैं। और is_active
को छोड़ना कॉलम deleted_at is null
क्वेरी 280 मिसे में निष्पादित होती है।
ध्यान दें कि यह अभी भी एक यथार्थवादी परिदृश्य नहीं है। आप शायद ही 1M में से 990K पंक्तियों का चयन करना चाहेंगे और इसे उपयोगकर्ता तक पहुंचाएंगे। संभवतः आपके पास तालिका में अधिक कॉलम (शायद टेक्स्ट सहित) होंगे। लेकिन यह दर्शाता है, कि आपको संभवतः is_active
. की आवश्यकता नहीं है कॉलम (यदि यह अतिरिक्त जानकारी नहीं जोड़ता है), और यह कि कोई भी अनुक्रमणिका सबसे अच्छी स्थिति में गैर-हटाई गई प्रविष्टियों का चयन करने के लिए बेकार है।
हालांकि एक अनुक्रमणिका हटाई गई पंक्तियों का चयन करने के लिए उपयोगी हो सकती है:
SELECT * FROM test WHERE is_active = 0;
इंडेक्स के साथ 10 मिलीसेकंड में और इंडेक्स के बिना 170 मिसे में निष्पादित होता है।
SELECT * FROM test WHERE deleted_at is not null;
इंडेक्स के साथ 11 मिलीसेकंड में और इंडेक्स के बिना 167 मिसे में निष्पादित होता है।
is_active
को छोड़ना कॉलम यह इंडेक्स के साथ 4 मिसे और इंडेक्स के बिना 150 मिसे में निष्पादित करता है।
इसलिए यदि यह परिदृश्य किसी तरह आपके डेटा के अनुकूल है तो निष्कर्ष यह होगा:is_active
को छोड़ दें कॉलम और deleted_at
. पर एक इंडेक्स न बनाएं कॉलम यदि आप शायद ही कभी हटाई गई प्रविष्टियों का चयन कर रहे हैं। या बेंचमार्क को अपनी आवश्यकताओं के अनुसार समायोजित करें और अपना निष्कर्ष निकालें।