Mysql
 sql >> डेटाबेस >  >> RDS >> Mysql

अनुक्रमित बूलियन कॉलम बनाम डेटाटाइम कॉलम पर क्वेरी का प्रदर्शन

यहां 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 . पर एक इंडेक्स न बनाएं कॉलम यदि आप शायद ही कभी हटाई गई प्रविष्टियों का चयन कर रहे हैं। या बेंचमार्क को अपनी आवश्यकताओं के अनुसार समायोजित करें और अपना निष्कर्ष निकालें।



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. उपयोगकर्ता खाता प्रबंधन, भूमिकाएँ, अनुमतियाँ, प्रमाणीकरण PHP और MySQL -- भाग 5

  2. EF कोर - तालिका '*.__EFMigrationsHistory' मौजूद नहीं है

  3. वाक्पटु का उपयोग करके डेटाबेस संबंध के आधार पर JSON प्रतिक्रिया का आदेश कैसे दें

  4. एसक्यूएल इंजेक्शन के लिए मुझे जिन प्रतीकों के बारे में पता होना चाहिए

  5. टेक्स्ट फ़ील्ड में एक कैटिड के लिए mysql खोज