মাইএসকিউএল কেন এই আদেশের জন্য বল প্রয়োগ করে সূচকে উপেক্ষা করে?


14

আমি একটি চালান EXPLAIN:

mysql> explain select last_name from employees order by last_name;
+----+-------------+-----------+------+---------------+------+---------+------+-------+----------------+  
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows  | Extra          |
+----+-------------+-----------+------+---------------+------+---------+------+-------+----------------+  
|  1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL | 10031 | Using filesort |
+----+-------------+-----------+------+---------------+------+---------+------+-------+----------------+  
1 row in set (0.00 sec)  

আমার টেবিলের সূচকগুলি:

mysql> show index from employees;  
+-----------+------------+---------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+  
| Table     | Non_unique | Key_name      | Seq_in_index | Column_name   | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |  
+-----------+------------+---------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+  
| employees |          0 | PRIMARY       |            1 | subsidiary_id | A         |           6 |     NULL | NULL   |      | BTREE      |         |               |  
| employees |          0 | PRIMARY       |            2 | employee_id   | A         |       10031 |     NULL | NULL   |      | BTREE      |         |               |  
| employees |          1 | idx_last_name |            1 | last_name     | A         |       10031 |      700 | NULL   |      | BTREE      |         |               |  
| employees |          1 | date_of_birth |            1 | date_of_birth | A         |       10031 |     NULL | NULL   | YES  | BTREE      |         |               |  
| employees |          1 | date_of_birth |            2 | subsidiary_id | A         |       10031 |     NULL | NULL   |      | BTREE      |         |               |  
+-----------+------------+---------------+--------------+---------------+-----------+-------------+----------+--------+------+------------+---------+---------------+  
5 rows in set (0.02 sec)  

সর্বশেষ নামটিতে একটি সূচক রয়েছে তবে অপ্টিমাইজারটি এটি ব্যবহার করে না।
সুতরাং আমি করি:

mysql> explain select last_name from employees force index(idx_last_name) order by last_name;  
+----+-------------+-----------+------+---------------+------+---------+------+-------+----------------+  
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows  | Extra          |  
+----+-------------+-----------+------+---------------+------+---------+------+-------+----------------+  
|  1 | SIMPLE      | employees | ALL  | NULL          | NULL | NULL    | NULL | 10031 | Using filesort |  
+----+-------------+-----------+------+---------------+------+---------+------+-------+----------------+  
1 row in set (0.00 sec)  

কিন্তু এখনও সূচি না ব্যবহার করেছেন! আমি এখানে কি ভুল করছি?
সূচকের সাথে এটির কি সম্পর্ক আছে NON_UNIQUE? বিটিডাব্লু সর্বশেষ নামটিVARCHAR(1000)

আপডেট @ রোল্যান্ডোমাইএসকিউএলডিবিএ দ্বারা অনুরোধ করা হয়েছে

mysql> SELECT COUNT(DISTINCT last_name) DistinctCount FROM employees;  
+---------------+  
| DistinctCount |  
+---------------+  
|         10000 |  
+---------------+  
1 row in set (0.05 sec)  


mysql> SELECT COUNT(1) FROM (SELECT COUNT(1) Count500,last_name FROM employees GROUP BY last_name HAVING COUNT(1) > 500) A;  
+----------+  
| COUNT(1) |  
+----------+  
|        0 |  
+----------+  
1 row in set (0.15 sec)  

দয়া করে এই দুটি প্রশ্নের চালান: 1) SELECT COUNT(DISTINCT last_name) DistinctCount FROM employees;2) SELECT COUNT(1) FROM (SELECT COUNT(1) Count500,last_name FROM employees GROUP BY last_name HAVING COUNT(1) > 500) A;। প্রতিটি গণনার ফলাফল কী?
রোল্যান্ডোমাইএসকিউএলডিবিএ

@ রোল্যান্ডোমাইএসকিউএলডিবিএ: আপনি যে তথ্য চেয়েছিলেন তার সাথে আমি ওপি আপডেট করেছি।
ক্র্যাটিলাস

আরও দুটি প্রশ্ন, দয়া করে: 1) SELECT COUNT(1) FullTableCount FROM employees;এবং 2) SELECT * FROM (SELECT COUNT(1) Count500,last_name FROM employees GROUP BY last_name HAVING COUNT(1) > 500) A LIMIT 10;
RolandoMySQLDBA

কিছু মনে করবেন না, আমি আমার যা প্রয়োজন তা ব্যাখ্যাটি দেখতে পাচ্ছি।
RolandoMySQLDBA

2
@ ক্র্যাটিলাস আপনি একটি ভুল উত্তর গ্রহণ করেছেন, আপনি মাইকেল-স্ক্লবোটের
चमत्कार 173

উত্তর:


6

সমস্যা # 1

প্রশ্নটি দেখুন

select last_name from employees order by last_name;

আমি কোনও অর্থপূর্ণ যেখানে ক্লজটি দেখতে পাচ্ছি না এবং মাইএসকিউএল কোয়েরি অপ্টিমাইজারটিও দেখছি না। কোনও সূচক ব্যবহার করার কোনও উত্সাহ নেই।

সমস্যা # 2

প্রশ্নটি দেখুন

select last_name from employees force index(idx_last_name) order by last_name; 

আপনি এটিকে একটি সূচক দিয়েছেন, কিন্তু ক্যোরি অপ্টিমাইজারটি গ্রহণ করেছে। আমি এর আগে এই আচরণটি দেখেছি ( আমি কীভাবে জিনকে মাইএসকিউএল-তে একটি নির্দিষ্ট সূচক ব্যবহার করতে বাধ্য করব? )

কেন এমন হওয়া উচিত?

কোনও WHEREধারা ছাড়াই , ক্যোয়ারী অপ্টিমাইজার নিজেই নিম্নলিখিতটি বলে:

  • এটি একটি ইনোডিবি টেবিল
  • এটি একটি সূচকযুক্ত কলাম
  • সূচীতে জেন_ ক্লাস্ট_ইন্ডেক্সের সারি_আডি (ওরফে ক্লাস্টারড ইনডেক্স) রয়েছে
  • কেন আমাকে সূচকের দিকে নজর দেওয়া উচিত
    • কোন WHEREধারা আছে?
    • আমি সবসময় টেবিল ফিরে বাউন করতে হবে?
  • যেহেতু একটি InnoDB টেবিলের সমস্ত সারিগুলি জেন_ক্লাস্ট_আইডেক্স হিসাবে একই 16 কে ব্লকে থাকে, আমি পরিবর্তে একটি পূর্ণ টেবিল স্ক্যান করব।

ক্যোয়ারী অপ্টিমাইজারটি সর্বনিম্ন প্রতিরোধের পথ বেছে নিয়েছিল।

আপনি কিছুটা ধাক্কা খাওয়ার জন্য যেতে যাচ্ছেন তবে এখানে এটি যায়: আপনি কি জানেন যে কোয়েরি অপ্টিমাইজারটি মাইআইএসএএমকে বেশ আলাদাভাবে পরিচালনা করবে?

আপনি সম্ভবত এইচইউএইচ বলছেন ???? কিভাবে ????

মাইআইএসএএম একটি .MYDফাইলে ডেটা এবং ফাইলের সমস্ত সূচী সঞ্চয় করে .MYI

একই ক্যোয়ারীটি একটি ভিন্ন ব্যাখ্যা পরিকল্পনা তৈরি করবে কারণ সূচকটি ডেটা থেকে আলাদা একটি ফাইলে বাস করে। কেন? এখানে কেন:

  • প্রয়োজনীয় ডেটা ( last_nameকলাম) ইতিমধ্যে অর্ডার করা হয়েছে.MYI
  • সবচেয়ে খারাপ ক্ষেত্রে, আপনার একটি সম্পূর্ণ সূচক স্ক্যান হবে
  • আপনি কেবল last_nameসূচি থেকে কলামটি অ্যাক্সেস করতে পারবেন
  • অযাচিত মাধ্যমে আপনার চালনার দরকার নেই
  • আপনি বাছাইয়ের জন্য টেম্প ফাইল ফাইলটি ট্রিগার করবেন না

কীভাবে এ বিষয়ে নিশ্চিত হতে পারে? আমি এই ওয়ার্কিং থিয়োরিটি পরীক্ষা করেছি যে কীভাবে একটি আলাদা স্টোরেজ ব্যবহার করে আলাদা আলাদা এক্সপ্ল্যান প্ল্যান তৈরি করা যায় (কখনও কখনও এটি আরও ভাল হয়): অর্ডার দ্বারা ব্যবহারের জন্য কোনও নির্বাচিত সমস্ত কলামকে একটি সূচী আবশ্যক?


1
-১ @ রোল্যান্ডো এই উত্তরটি মাইকেল-স্ক্লবোটের সঠিক উত্তরের চেয়ে কম সুনির্দিষ্ট নয় তবে এটি ভুল, উদাহরণস্বরূপ ম্যানুয়ালটি বলে: "মাইএসকিউএল এই ক্রিয়াকলাপগুলির জন্য সূচকগুলি ব্যবহার করে: (...) বাছাই বা একটি টেবিলকে শ্রেণিবদ্ধ করা যদি বাছাই বা গোষ্ঠীকরণ একটি ব্যবহারযোগ্য সূচক (...) "এর বামতম উপসর্গে করা হয়। এছাড়াও আপনার পোস্টের অন্যান্য বিবৃতি বিতর্কিত। আমি আপনাকে এই উত্তরটি মুছতে বা পুনরায় কাজ করার পরামর্শ দিচ্ছি।
चमत्कार 173

এই উত্তরটি সঠিক নয়। বাছাই এড়ানো যদি কোনও শৃঙ্খলা না থাকা সত্ত্বেও একটি সূচক ব্যবহার করা যেতে পারে।

19

প্রকৃতপক্ষে, এখানে সমস্যাটি হ'ল এটি প্রিফিক্স সূচকের মতো দেখাচ্ছে। আমি প্রশ্নের টেবিল সংজ্ঞা দেখতে পাচ্ছি না, তবে sub_part= 700? আপনি পুরো কলামটি সূচী করেননি, তাই সূচিটি বাছাইয়ের জন্য ব্যবহার করা যাবে না এবং এটি কোনও কভারিং সূচক হিসাবে কার্যকর নয়। এটি কেবল সারিগুলি সন্ধান করতে ব্যবহৃত হতে পারে যা "সম্ভবত" একটি WHEREএবং সার্ভার স্তরটির সাথে মেলে (স্টোরেজ ইঞ্জিনের উপরে) সারিগুলিকে আরও ফিল্টার করতে হবে। কোনও শেষ নামটির জন্য আপনার কি সত্যই 1000 টি অক্ষর দরকার?


উদাহরণস্বরূপ আপডেট করুন: আমার কাছে 500 টিরও বেশি সারি লিটল সহ একটি টেবিল পরীক্ষার টেবিল রয়েছে, প্রতিটি কলামে একটি ওয়েব সাইটের ডোমেন নাম domain_name VARCHAR(254) NOT NULLএবং কোনও সূচক নেই।

mysql> alter table keydemo add key(domain_name);
Query OK, 0 rows affected (0.17 sec)
Records: 0  Duplicates: 0  Warnings: 0

পূর্ণ কলাম ইনডেক্স করা সহ, ক্যোয়ারী সূচকটি ব্যবহার করে:

mysql> explain select domain_name from keydemo order by domain_name;
+----+-------------+---------+-------+---------------+-------------+---------+------+------+-------------+
| id | select_type | table   | type  | possible_keys | key         | key_len | ref  | rows | Extra       |
+----+-------------+---------+-------+---------------+-------------+---------+------+------+-------------+
|  1 | SIMPLE      | keydemo | index | NULL          | domain_name | 764     | NULL |  541 | Using index |
+----+-------------+---------+-------+---------------+-------------+---------+------+------+-------------+
1 row in set (0.01 sec)

সুতরাং, এখন, আমি সেই সূচকটি ছেড়ে দেব, এবং কেবলমাত্র ডোমেন_নামের প্রথম 200 টি অক্ষরকে সূচক করব।

mysql> alter table keydemo drop key domain_name;
Query OK, 0 rows affected (0.11 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> alter table keydemo add key(domain_name(200));
Query OK, 0 rows affected (0.08 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> explain select domain_name from keydemo order by domain_name;
+----+-------------+---------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows | Extra          |
+----+-------------+---------+------+---------------+------+---------+------+------+----------------+
|  1 | SIMPLE      | keydemo | ALL  | NULL          | NULL | NULL    | NULL |  541 | Using filesort |
+----+-------------+---------+------+---------------+------+---------+------+------+----------------+
1 row in set (0.00 sec)

mysql>

Voila।

আরও মনে রাখবেন, সূচিটি 200 অক্ষরে, কলামের দীর্ঘতম মানের চেয়ে দীর্ঘ ...

mysql> select max(length(domain_name)) from keydemo;
+--------------------------+
| max(length(domain_name)) |
+--------------------------+
|                       43 |
+--------------------------+
1 row in set (0.04 sec)

... তবে এতে কোনও তফাত হয় না। একটি উপসর্গ দৈর্ঘ্যের সাথে ঘোষিত একটি সূচক কেবলমাত্র অনুসন্ধানের জন্য ব্যবহার করা যেতে পারে, বাছাইয়ের জন্য নয় এবং আচ্ছাদন সূচক হিসাবে নয়, কারণ এটিতে সংজ্ঞা অনুসারে পূর্ণ কলাম মান থাকে না।

এছাড়াও, উপরোক্ত প্রশ্নগুলি একটি ইনোডিবি টেবিলে চালানো হয়েছিল, তবে মাইএসএএম টেবিলে এগুলি চালানো কার্যত অভিন্ন ফলাফল দেয়। শুধুমাত্র এই ক্ষেত্রে পার্থক্য হল যে InnoDB গণনা জন্য rowsবন্ধ (541) সামান্য থাকাকালীন MyISAM শো সারি সঠিক সংখ্যা (563) যা স্বাভাবিক আচরণ, যেহেতু দুই স্টোরেজ ইঞ্জিন সূচক ধনী হ্যান্ডেল খুব ভিন্নভাবে।

আমি এখনও দৃ would়ভাবে বলব যে শেষের নামটির কলামটি প্রয়োজনের তুলনায় সম্ভবত বড় but তবে আপনি যদি InnoDB ব্যবহার করছেন এবং মাইএসকিউএল 5.5 বা 5.6 ব্যবহার করছেন তবে সম্পূর্ণ কলামটি সূচী করা সম্ভব :

ডিফল্টরূপে, একটি একক-কলাম সূচকের জন্য একটি সূচক কী 767 বাইট পর্যন্ত হতে পারে। একই দৈর্ঘ্যের সীমা যে কোনও সূচি কী উপসর্গের জন্য প্রযোজ্য। বিভাগ 13.1.13, " CREATE INDEXসিনট্যাক্স" দেখুন। উদাহরণস্বরূপ, আপনি প্রতিটি অক্ষরের জন্য একটি অক্ষর সেট এবং সর্বোচ্চ 3 বাইট ধরে ধরে একটি কলাম TEXTবা 255 টিরও বেশি অক্ষরের কলাম উপসর্গ সূচী দিয়ে এই সীমাটি হিট করতে পারেন । যখন কনফিগারেশন বিকল্প সক্ষম করা থাকে, সারণী এবং সারি বিন্যাসগুলি ব্যবহার করে এমন সারণীর জন্য এই দৈর্ঘ্য সীমাটি 3072 বাইটে বাড়ানো হয় ।VARCHARUTF-8innodb_large_prefixInnoDBDYNAMICCOMPRESSED

- http://dev.mysql.com/doc/refman/5.5/en/innodb-restrictions.html


আকর্ষণীয় দৃষ্টিকোণ। কলামটি varchar(1000)কিন্তু এটি সূচকের পক্ষে অনুমোদিত সর্বোচ্চের বাইরে যা ~ 750
ক্র্যাটিলাস

8
এই উত্তরটি গ্রহণযোগ্য হওয়া উচিত।
ypercubeᵀᴹ

1
@ টাইপ्यूब এই উত্তরটি আমার চেয়ে আরও সুনির্দিষ্ট। আপনার মন্তব্যের জন্য +1 এবং এই উত্তরের জন্য +1 করুন। এটি আমার পরিবর্তে গ্রহণ করা উচিত।
রোল্যান্ডোমাইএসকিউএলডিবিএ

1
@ টিমো, এটি একটি আকর্ষণীয় প্রশ্ন ... যা আমি এখানে একটি নতুন প্রশ্ন হিসাবে পোস্ট করার পরামর্শ দেব, সম্ভবত, এই উত্তরটির লিঙ্ক সহ, প্রসঙ্গে for থেকে সম্পূর্ণ আউটপুট পোস্ট EXPLAIN SELECT ..., সেইসাথে SHOW CREATE TABLE ...এবং SELECT @@VERSION;সংস্করণ জুড়ে অপটিমাইজার পরিবর্তন যেহেতু প্রাসঙ্গিক হতে পারে।
মাইকেল - sqlbot

1
এখনই আমি প্রতিবেদন করতে পারি যে (কমপক্ষে 5.7 এর জন্য) একটি উপসর্গ সূচক সূচকে নালায় সহায়তা করে না , যেমন আমি উপরে আমার মন্তব্যে জিজ্ঞাসা করেছি।
টিমো

2

আমি এর সম্পর্কে একটি উত্তর দিয়েছি কারণ একটি মন্তব্য গঠন গঠনের পক্ষে সমর্থন করবে না এবং রোল্যান্ডোমাইএসকিউএল ডিবিএ জেন_ক্লাস্ট_আইএনডেক্স এবং ইনানোডব সম্পর্কে কথা বলেছিল। এবং এটি একটি ইনোডাব ভিত্তিক টেবিলে খুব গুরুত্বপূর্ণ। এটি সাধারণ ডিবিএ জ্ঞানের চেয়ে আরও বেশি যায় কারণ আপনাকে সি কোড বিশ্লেষণ করতে সক্ষম হতে হবে ..

আপনি যদি ইনোডব ব্যবহার করে থাকেন তবে আপনার সর্বদা একটি প্রাথমিক কী বা একটি অনন্য কী করা উচিত। যদি আপনি ইন্নাডব না করেন তবে এটি নিজস্ব উত্পাদিত ROW_ID ব্যবহার করবে যা আপনাকে ভালোর চেয়ে আরও বেশি ক্ষতি করতে পারে।

আমি এটিকে সহজভাবে ব্যাখ্যা করার চেষ্টা করব কারণ প্রমাণটি সি কোডের উপর ভিত্তি করে।

/**********************************************************************//**
Returns a new row id.
@return the new id */
UNIV_INLINE
row_id_t
dict_sys_get_new_row_id(void)
/*=========================*/
{
    row_id_t    id;

    mutex_enter(&(dict_sys->mutex));

    id = dict_sys->row_id;

    if (0 == (id % DICT_HDR_ROW_ID_WRITE_MARGIN)) {
          dict_hdr_flush_row_id();
    }

    dict_sys->row_id++;
    mutex_exit(&(dict_sys->mutex));
    return(id);
}

প্রথম সমস্যা

mutex_enter (& (dict_sys-> mutex));

এই লাইনটি নিশ্চিত করে যে একই সময়ে কেবল একটি থ্রেড ডিক_সিস-> মিটেক্স অ্যাক্সেস করতে পারে। যদি ইতিমধ্যে মানটি নিঃশব্দ করা হয়ে থাকে ... হ্যাঁ একটি থ্রেড অপেক্ষা করতে হবে যাতে আপনার কাছে থ্রেড লক করার মতো সুন্দর এলোমেলো বৈশিষ্ট্যের মতো কিছু পাওয়া যায় বা যদি আপনার নিজস্ব প্রাথমিক কী বা অনন্য কী ছাড়া আপনার আরও টেবিল থাকে তবে আপনার সাথে একটি দুর্দান্ত বৈশিষ্ট্য থাকবে ইনোডাব ' টেবিল লকিং ' এ কারণেই নয় যে মাইআইএসএএম-কে ইনোডিবি দ্বারা প্রতিস্থাপন করা হয়েছিল কারণ রেকর্ড / সারি ভিত্তিক লকিং নামক দুর্দান্ত বৈশিষ্ট্যটি বন্ধ করে দেওয়া হয় ..

দ্বিতীয় সমস্যা

(0 == (আইডি% DICT_HDR_ROW_ID_WRITE_MARGIN))

মডেলো (%) গণনাগুলি ধীরে ধীরে ভাল না আপনি যদি ব্যাচ সন্নিবেশ করান কারণ এটি প্রতিবারই পুনরায় গণনা করা দরকার ..., এবং কারণ DICT_HDR_ROW_ID_WRITE_MARGIN (মান 256) দুটি একটি শক্তি যা এটি আরও দ্রুত তৈরি করা যেতে পারে ..

(0 == (আইডি এবং (DICT_HDR_ROW_ID_WRITE_MARGIN - 1)))

সাইড নোট যদি সি সংকলকটি অনুকূলকরণের জন্য কনফিগার করা থাকে এবং এটি একটি ভাল অপ্টিমাইজার হয়, সি অপ্টিমাইজারটি হালকা সংস্করণে "ভারী" কোডটি ঠিক করবে

গল্পের মূলমন্ত্রটি সর্বদা আপনার নিজস্ব মূল কী তৈরি করুন বা আপনি যখন প্রথম থেকেই কোনও টেবিল তৈরি করেন তখন আপনার অনন্য সূচী রয়েছে তা নিশ্চিত করুন


সারি-ভিত্তিক প্রতিলিপি যুক্ত করুন এবং সারি আইডি সার্ভারগুলিতে সামঞ্জস্যপূর্ণ নয় এবং সর্বদা একটি প্রাথমিক কী তৈরির বিষয়ে রেমন্ডের বক্তব্য আরও গুরুত্বপূর্ণ।

দয়া করে UNIQUEএটি পর্যাপ্ত বলে প্রস্তাব করবেন না - একে অনন্য সূচককে পিকে উন্নীত করতে কেবল নন-নুল কলামগুলিও অন্তর্ভুক্ত করতে হবে।
রিক জেমস

"মডুলো (%) গণনা ধীর" - আরও গুরুত্বপূর্ণ যে INSERTএই ফাংশনে কোন সময়ের কত শতাংশ সময় ব্যয় করা হয়। আমার সন্দেহ হয় তুচ্ছ। আশেপাশে কলামগুলি বেলন করার প্রচেষ্টার বিপরীতে বিট্রি অপারেশনগুলি করুন, মাঝে মাঝে ব্লক-স্প্লিট, বাফারপুলের বিভিন্ন মিটেক্সস, চেঞ্জ-বাফার স্টাফ ইত্যাদিসহ ইত্যাদি
রিক জেমস

সত্য @ রিক জেমস ওভারহেড খুব অল্প সংখ্যক হতে পারে তবে অনেকগুলি ছোট সংখ্যাও যোগ করে দেয় (তবুও এটি একটি মাইক্রো অপ্টিমাইজেশান হবে) .. এছাড়াও প্রথম সমস্যাটি সবচেয়ে বেশি সমস্যা হয়
রেমন্ড নিজল্যান্ড
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.