mysql5.5索引,MySQL--5索引选择原则
大家好我是安小生,這篇文章講述索引的選擇原則。
1.explain分析語句。
explain:通常是用于sql語句性能分析。
舉個栗子:
explain select * from user where name = "張三"
我們來看一下explain 查詢出來的字段都是什么?
id:select識別符。
1.select_type
(1) SIMPLE
SIMPLE表示簡單查詢,其中不包括連接查詢和子查詢。
(2) PRIMARY與SUBQUERY
PRIMARY表示主查詢或者最外層的查詢語句。SUBQUERY : 子查詢
mysql> explain select * from article where id = (select id from article where content = 'LrQ2Ievq9P');
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+----------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+----------+----------+-------------+
| 1 | PRIMARY | article | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL |
| 2 | SUBQUERY | article | NULL | ALL | NULL | NULL | NULL | NULL | 10856301 | 10.00 | Using where |
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+----------+----------+-------------+
2 rows in set, 1 warning (16.28 sec)
(3) DERIVED: 衍生查詢-在select出一批自定義列的數據,概念上相當于一張表,但是該表只在語句執行過程出現和
(4) UNION 與 UNION RESULT
UNION :聯合查詢,union 后面的那張表就會表示成它
UNION RESULT: 聯合結果
例如:
mysql> explain select * from article where id = 6565544 union all select * from article where id = 8484848 ;
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
| 1 | PRIMARY | article | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL |
| 2 | UNION | article | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL |
+----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------+
2 rows in set, 1 warning (0.00 sec)
其他字段的意思:
table:與查詢語句相關的表
partitions:表分區
type:表的連接類型
all index range ref null const
possible_keys:可能使用到的索引
key:使用的索引
key_len:使用的索引長度
ref:使用哪個列一起進行的查詢
rows:查詢sql語句掃描的數據量,比不會很精確 屬于約等于
2.type詳細介紹
對表訪問方式,表示MySQL在表中找到所需行的方式,又稱“訪問類型”。
常用的類型有: ALL、index、range、 ref、eq_ref、const、system、NULL(從左到右,性能從差到好)
ALL:Full Table Scan, MySQL將遍歷全表以找到匹配的行
-** index**: Full Index Scan,index與ALL區別為index類型只遍歷索引樹
range:只檢索給定范圍的行,使用一個索引來選擇行
ref: 表示上述表的連接匹配條件,即哪些列或常量被用于查找索引列上的值
eq_ref: 類似ref,區別就在使用的索引是唯一索引,對于每個索引鍵值,表中只有一條記錄匹配,簡單來說,就是多表連接中使用primary key或者 unique key作為關聯條件
const、system: 當MySQL對查詢某部分進行優化,并轉換為一個常量時,使用這些類型訪問。如將主鍵置于where列表中,MySQL就能將該查詢轉換為一個常量,system是const類型的特例,當查詢的表只有一行的情況下,使用system
NULL: MySQL在優化過程中分解語句,執行時甚至不用訪問表或索引,例如從一個索引列里選取最小值可以通過單獨索引查找完成。
3. Extar
Extra列是用來說明一些額外信息的,我們可以通過這些額外信息來更準確的理解MySQL到底將如何執行給定的查詢語句。MySQL提供的額外信息有好幾十個,就不一個一個介紹了,在這只介紹常見的一些額外信息說明 。
Using filesort: 如果根據索引列進行排序(order by 索引列)是可以用到索引的,SQL查詢引擎會先根據索引列進行排序,然后獲取對應記錄的主鍵id執行回表操作,如果排序字段用不到索引則只能在內存中或磁盤中進行排序操作,MySQL把這種在內存或者磁盤上進行排序的方式統稱為文件排序(英文名:filesort),如果某個查詢需要使用文件排序的方式執行查詢,就會在執行計劃的Extra列中顯示Using filesort
Using temporary: 許多查詢的執行過程中,MySQL會借助臨時表來完成一些功能,比如去重、排序之類的,比如我們在執行許多包含distinct、group by、union等子句的查詢過程中,如果不能有效利用索引來完成查詢,MySQL很有可能尋求通過建立內部的臨時表來執行查詢。如果查詢中使用到了內部的臨時表,在執行計劃的Extra列將會顯示Using temporary提示.
USING index: 表示相應的select操作中使用了覆蓋索引(Covering Index),避免回表操作,效率不錯!
如果同時出現using where,表明索引被用來執行索引鍵值的查找;如果沒有同時出現using where,表名索引用來讀取數據而非執行查找動作。
Using where: 使用了where過濾
using join buffer: 在連接查詢執行過程中,當被驅動表不能有效的利用索引加快訪問速度,MySQL一般會為其分配一塊名叫join buffer的內存塊來加快查詢速度
impossible where: where子句的值總是false,不能用來獲取任何元組
select tables optimized away: 在沒有GROUPBY子句的情況下,基于索引優化MIN/MAX操作或者對于MyISAM存儲引擎優化COUNT(*)操作,不必等到執行階段再進行計算,查詢執行計劃生成的階段即完成優化。
distinct: 優化distinct,在找到第一匹配的元組后即停止找同樣值的工作
Using index condition:查找使用了索引,但是需要回表查詢數據
1.2 profile分析
當我們要對某一條sql的性能進行分析時,可以使用它。
Profiling是從 mysql5.0.3版本以后才開放的。啟動profile之后,所有查詢包括錯誤的語句都會記錄在內。 關閉會話或者set profiling=0 就關閉了。(如果將profiling_history_size參數設置為0,同樣具有關閉MySQL的profiling效果。
此工具可用來查詢SQL執行狀態,System lock和Table lock 花多少時間等等,
對定位一條語句的I/O消耗和CPU消耗 非常重要。(SQL 語句執行所消耗的最大兩部分資源就是IO和CPU)
--在mysql5.7之后,profile信息將逐漸被廢棄,mysql推薦使用performance schema
開啟以及使用過程
set profiling=1; //打開分析
mysql> show profiles;
+----------+------------+---------------------------------------------------------------------------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+---------------------------------------------------------------------------------------------------------+
| 1 | 0.00034350 | select * from staffs where name = "shine" |
| 2 | 0.00038350 | select id,`name`,city,monthsalary,gender from customers1s where city="" and gender=0 and monthsalary=99 |
+----------+------------+---------------------------------------------------------------------------------------------------------+
2 rows in set, 1 warning (0.01 sec)
select * from staffs where name = "shine";
select id,`name`,city,monthsalary,gender from customers1s where city="" and gender=0 and monthsalary=99;
show profile for query 1; //查看sql1的具體分析
mysql> show profile for query 1;
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000106 |
| checking permissions | 0.000006 |
| Opening tables | 0.000037 |
| init | 0.000005 |
| System lock | 0.000009 |
| optimizing | 0.000010 |
| statistics | 0.000064 |
| preparing | 0.000007 |
| executing | 0.000002 |
| Sending data | 0.000038 |
| end | 0.000002 |
| query end | 0.000006 |
| closing tables | 0.000004 |
| freeing items | 0.000041 |
| cleaning up | 0.000008 |
+----------------------+----------+
15 rows in set, 1 warning (0.01 sec)
show profile ALL for query 1; //查看sql1相關的所有分析【主要看i/o與cpu,下邊分析中有各項意義介紹】
mysql> show profile ALL for query 1;
+----------------------+----------+----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+----------------------+-------------+
| Status | Duration | CPU_user | CPU_system | Context_voluntary | Context_involuntary | Block_ops_in | Block_ops_out | Messages_sent | Messages_received | Page_faults_major | Page_faults_minor | Swaps | Source_function | Source_file | Source_line |
+----------------------+----------+----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+----------------------+-------------+
| starting | 0.000106 | 0.000000 | 0.000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
| checking permissions | 0.000006 | 0.000000 | 0.000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | check_access | sql_authorization.cc | 1892 |
| Opening tables | 0.000037 | 0.000000 | 0.000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | open_tables | sql_base.cc | 5526 |
| init | 0.000005 | 0.000000 | 0.000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Sql_cmd_dml::execute | sql_select.cc | 514 |
| System lock | 0.000009 | 0.000000 | 0.000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | mysql_lock_tables | lock.cc | 332 |
| optimizing | 0.000010 | 0.000000 | 0.000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | JOIN::optimize | sql_optimizer.cc | 213 |
| statistics | 0.000064 | 0.000000 | 0.000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | JOIN::optimize | sql_optimizer.cc | 422 |
| preparing | 0.000007 | 0.000000 | 0.000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | JOIN::optimize | sql_optimizer.cc | 496 |
| executing | 0.000002 | 0.000000 | 0.000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | JOIN::exec | sql_executor.cc | 210 |
| Sending data | 0.000038 | 0.000000 | 0.000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | JOIN::exec | sql_executor.cc | 285 |
| end | 0.000002 | 0.000000 | 0.000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Sql_cmd_dml::execute | sql_select.cc | 564 |
| query end | 0.000006 | 0.000000 | 0.000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | mysql_execute_command | sql_parse.cc | 4310 |
| closing tables | 0.000004 | 0.000000 | 0.000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | mysql_execute_command | sql_parse.cc | 4356 |
| freeing items | 0.000041 | 0.000000 | 0.000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | mysql_parse | sql_parse.cc | 4968 |
| cleaning up | 0.000008 | 0.000000 | 0.000000 | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | dispatch_command | sql_parse.cc | 1978 |
+----------------------+----------+----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+----------------------+-------------+
15 rows in set, 1 warning (0.00 sec)
set profiling=0; //關閉分析
性能結果分析
SQL:show profile [type] for query 1 [limit m offsetn]
字段描述:
+----------------------+----------+----------+------------+
"Status": "query end", 狀態
"Duration": "1.751142", 持續時間
"CPU_user": "0.008999", cpu用戶
"CPU_system": "0.003999", cpu系統
"Context_voluntary": "98", 上下文主動切換
"Context_involuntary": "0", 上下文被動切換
"Block_ops_in": "8", 阻塞的輸入操作
"Block_ops_out": "32", 阻塞的輸出操作
"Messages_sent": "0", 消息發出
"Messages_received": "0", 消息接受
"Page_faults_major": "0", 主分頁錯誤
"Page_faults_minor": "0", 次分頁錯誤
"Swaps": "0", 交換次數
"Source_function": "mysql_execute_command", 源功能
"Source_file": "sql_parse.cc", 源文件
"Source_line": "4465" 源代碼行
+----------------------+----------+----------+------------+
值解釋:
+----------------------+----------+----------+------------+
starting:開始
checking permissions:檢查權限
Opening tables:打開表
init : 初始化
System lock :系統鎖
optimizing : 優化
statistics : 統計
preparing :準備
executing :執行
Sending data :發送數據
Sorting result :排序
end :結束
query end :查詢 結束
closing tables : 關閉表 /去除TMP 表
freeing items : 釋放物品
cleaning up :清理
+----------------------+----------+----------+------------+
2. 聯合索引結構與索引匹配原則
最左前綴匹配原則:在MySQL建立聯合索引時會遵守最左前綴匹配原則,即最左優先,在檢索數據時從聯合索引的最左邊開始匹配。
要想理解聯合索引的最左匹配原則,先來理解下索引的底層原理。索引的底層是一顆B+樹,那么聯合索引的底層也就是一顆B+樹,只不過聯合索引的B+樹節點中存儲的是鍵值。由于構建一棵B+樹只能根據一個值來確定索引關系,所以數據庫依賴聯合索引最左的字段來構建。
舉例:創建一個(a,b)的聯合索引,那么它的索引樹就是下圖的樣子。
最左原則圖.png
可以看到a的值是有順序的,1,1,2,2,3,3,而b的值是沒有順序的1,2,1,4,1,2。
但是我們又可發現a在等值的情況下,b值又是按順序排列的,但是這種順序是相對的。這是因為MySQL創建聯合索引的規則是首先會對聯合索引的最左邊第一個字段排序,在第一個字段的排序基礎上,然后在對第二個字段進行排序。所以b=2這種查詢條件沒有辦法利用索引。
字段 類型 描述
id int(11) 主鍵
name varchar(10) 名稱
age int(11) 年齡
該表中對id列.name列.age列建立了一個聯合索引 id_name_age_index,實際上相當于建立了三個索引(id)(id_name)(id_name_age)。
下面介紹下可能會使用到該索引的幾種情況:
1.全值匹配查詢時
mysql> explain select * from staffs where name = 'shine' and sex = 1 and age = 20;
+----+-------------+--------+------------+------+------------------+------------------+---------+-------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+------------------+------------------+---------+-------------------+------+----------+-------------+
| 1 | SIMPLE | staffs | NULL | ref | idx_name_age_sex | idx_name_age_sex | 40 | const,const,const | 1 | 100.00 | Using index |
+----+-------------+--------+------------+------+------------------+------------------+---------+-------------------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from staffs where age = 20 and name = 'shine' and sex = 1;
+----+-------------+--------+------------+------+------------------+------------------+---------+-------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+------------------+------------------+---------+-------------------+------+----------+-------------+
| 1 | SIMPLE | staffs | NULL | ref | idx_name_age_sex | idx_name_age_sex | 40 | const,const,const | 1 | 100.00 | Using index |
+----+-------------+--------+------------+------+------------------+------------------+---------+-------------------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from staffs where sex = 1 and age = 20 and name = 'shine';
+----+-------------+--------+------------+------+------------------+------------------+---------+-------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+------------------+------------------+---------+-------------------+------+----------+-------------+
| 1 | SIMPLE | staffs | NULL | ref | idx_name_age_sex | idx_name_age_sex | 40 | const,const,const | 1 | 100.00 | Using index |
+----+-------------+--------+------------+------+------------------+------------------+---------+-------------------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
通過觀察上面的結果圖可知,where后面的查詢條件,不論是使用(name,age,sex)(age,name,sex)還是(sex,age,name)順序,在查詢時都使用到了聯合索引,可能有同學會疑惑,為什么底下兩個的搜索條件明明沒有按照聯合索引從左到右進行匹配,卻也使用到了聯合索引? 這是因為MySQL中有查詢優化器explain,所以sql語句中字段的順序不需要和聯合索引定義的字段順序相同,查詢優化器會判斷糾正這條SQL語句以什么樣的順序執行效率高,最后才能生成真正的執行計劃,所以不論以何種順序都可使用到聯合索引。
匹配最左邊列時
mysql> explain select * from staffs where name = 'shine';
+----+-------------+--------+------------+------+------------------+------------------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+------------------+------------------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | staffs | NULL | ref | idx_name_age_sex | idx_name_age_sex | 33 | const | 1 | 100.00 | Using index |
+----+-------------+--------+------------+------+------------------+------------------+---------+-------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
該搜索是遵循最左匹配原則的,通過key字段也可知,在搜索過程中使用到了聯合索引,且使用的是聯合索引中的(id)索引
mysql> explain select * from staffs where name = 'shine' and age = 20;
+----+-------------+--------+------------+------+------------------+------------------+---------+-------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+------------------+------------------+---------+-------------+------+----------+-------------+
| 1 | SIMPLE | staffs | NULL | ref | idx_name_age_sex | idx_name_age_sex | 38 | const,const | 1 | 100.00 | Using index |
+----+-------------+--------+------------+------+------------------+------------------+---------+-------------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
由于name到age是從左邊依次往右邊匹配,這兩個字段中的值都是有序的,所以也遵循最左匹配原則,通過key字段可知,在搜索過程中也使用到了聯合索引,但使用的是聯合索引中的(name_age)索引
mysql> explain select * from staffs where name = 'shine' and age = 20 and sex = 1;
+----+-------------+--------+------------+------+------------------+------------------+---------+-------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+------------------+------------------+---------+-------------------+------+----------+-------------+
| 1 | SIMPLE | staffs | NULL | ref | idx_name_age_sex | idx_name_age_sex | 40 | const,const,const | 1 | 100.00 | Using index |
+----+-------------+--------+------------+------+------------------+------------------+---------+-------------------+------+----------+-------------+
1 row in set, 1 warning (0.01 sec)
由于上面三個搜索都是從最左邊name依次向右開始匹配的,所以都用到了name_age_sex聯合索引。
那如果不是依次匹配呢?
mysql> mysql> explain select * from staffs where name = 'shine' and sex = 1;
+----+-------------+--------+------------+------+------------------+------------------+---------+-------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+------------------+------------------+---------+-------+------+----------+--------------------------+
| 1 | SIMPLE | staffs | NULL | ref | idx_name_age_sex | idx_name_age_sex | 33 | const | 1 | 20.00 | Using where; Using index |
+----+-------------+--------+------------+------+------------------+------------------+---------+-------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)
通過key字段可知,在搜索過程中也使用到了聯合索引,但使用的是聯合索引中的(name)索引,因為聯合索引樹是按照name字段創建的,但sex相對于name來說是無序的,只有name是有序的,所以他只能使用聯合索引中的name索引。
mysql> explain select * from staffs where age = 20;
+----+-------------+--------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | staffs | NULL | index | NULL | idx_name_age_sex | 40 | NULL | 5 | 20.00 | Using where; Using index |
+----+-------------+--------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)
通過觀察發現上面key字段發現在搜索中也使用了name_age_sex索引,可能許多同學就會疑惑它并沒有遵守最左匹配原則,按道理會索引失效,為什么也使用到了聯合索引?因為沒有從id開始匹配,且name單獨來說是無序的,所以它確實不遵循最左匹配原則,然而從type字段可知,它雖然使用了聯合索引,但是它是對整個索引樹進行了掃描,正好匹配到該索引,與最左匹配原則無關,一般只要是某聯合索引的一部分,但又不遵循最左匹配原則時,都可能會采用index類型的方式掃描,但它的效率遠不如最做匹配原則的查詢效率高,index類型類型的掃描方式是從索引第一個字段一個一個的查找,直到找到符合的某個索引,與all不同的是,index是對所有索引樹進行掃描,而all是對整個磁盤的數據進行全表掃描。
mysql> explain select * from staffs where sex = 1;
+----+-------------+--------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | staffs | NULL | index | NULL | idx_name_age_sex | 40 | NULL | 5 | 20.00 | Using where; Using index |
+----+-------------+--------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from staffs where age = 20 and sex = 1;
+----+-------------+--------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | staffs | NULL | index | NULL | idx_name_age_sex | 40 | NULL | 5 | 20.00 | Using where; Using index |
+----+-------------+--------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)
這兩個結果跟上面的是同樣的道理,由于它們都沒有從最左邊開始匹配,所以沒有用到聯合索引,使用的都是index全索引掃描。
匹配列前綴
對于模糊匹配的查詢,如果是前綴匹配用的是索引,中墜和后綴用的是全表掃描
mysql> explain select * from staffs where name like "shie%";
+----+-------------+--------+------------+-------+------------------+------------------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+-------+------------------+------------------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | staffs | NULL | range | idx_name_age_sex | idx_name_age_sex | 33 | NULL | 1 | 100.00 | Using where; Using index |
+----+-------------+--------+------------+-------+------------------+------------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from staffs where name like "%ara%";
+----+-------------+--------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | staffs | NULL | index | NULL | idx_name_age_sex | 40 | NULL | 5 | 20.00 | Using where; Using index |
+----+-------------+--------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from staffs where name like "%ara";
+----+-------------+--------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | staffs | NULL | index | NULL | idx_name_age_sex | 40 | NULL | 5 | 20.00 | Using where; Using index |
+----+-------------+--------+------------+-------+---------------+------------------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)
3. mysql對于索引優先考慮的對象
一般我們在開發項目時對于一些業務難免會寫出一些條件+分組/排序的sql語句,而通常也是這些sql會導致mysql的性能變差,這個時候我們想到使用mysql的索引來進行優化,但是mysql的索引對于條件,分組,排序都存在的情況下是如何去選擇索引的呢?
下面我們根據上面的問題來進行一些測試以及分析。
條件與分組排序共存的情況下
mysql> explain select sex,age from staffs where name = "shine" group by sex order by age;
+----+-------------+--------+------------+------+--------------------------+------------------+---------+-------+------+----------+-----------------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+--------------------------+------------------+---------+-------+------+----------+-----------------------------------------------------------+
| 1 | SIMPLE | staffs | NULL | ref | idx_name_age_sex,idx_sex | idx_name_age_sex | 33 | const | 1 | 100.00 | Using where; Using index; Using temporary; Using filesort |
+----+-------------+--------+------------+------+--------------------------+------------------+---------+-------+------+----------+-----------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
當sql中where條件,分組,排序同時存在時,MySQL的優化器會優先選擇條件來確定使用的索引,因為where可以減少更多的sql掃描,而排序和分組往往進行的是全表掃描。
條件與排序共存
mysql> explain select sex,age from staffs where name = "shine" order by age;
+----+-------------+--------+------------+------+------------------+------------------+---------+-------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+------------------+------------------+---------+-------+------+----------+--------------------------+
| 1 | SIMPLE | staffs | NULL | ref | idx_name_age_sex | idx_name_age_sex | 33 | const | 1 | 100.00 | Using where; Using index |
+----+-------------+--------+------------+------+------------------+------------------+---------+-------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)
原因:所有的排序都是在條件過濾之后才執行的,所以如果條件過濾了大部分數據的話,幾百幾千條數據進行排序其實并不是很消耗性能,即使索引優化了排序但實際提升性能很有限。
分組排序共存
mysql> explain select sex,age from staffs group by sex order by age;
+----+-------------+--------+------------+-------+--------------------------+---------+---------+------+------+----------+---------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+-------+--------------------------+---------+---------+------+------+----------+---------------------------------+
| 1 | SIMPLE | staffs | NULL | index | idx_name_age_sex,idx_sex | idx_sex | 2 | NULL | 5 | 100.00 | Using temporary; Using filesort |
+----+-------------+--------+------------+-------+--------------------------+---------+---------+------+------+----------+---------------------------------+
1 row in set, 1 warning (0.00 sec)
對于分組和排序共存的情況下,mysql會優先根據分組去選擇索引,那是因為sql需要先將要查詢的數據進行分組,隨后才會進行數據的排序。
5. mysql索引的挑選原則
總結點:
注:字段一般是推薦重復比較少的字段影響到數據的檢索,如果是項目需求(可建立聯合索引)
唯一字段可以單獨建立單索引,非唯一考慮聯合索引,推薦盡量使用唯一字段建立索引
索引的個數,聯合索引的個數 最佳 6個 以內,如果索引因為項目需求:最多 10個
索引的使用遵循最左匹配原則其次覆蓋索引
盡量選擇小的字段建立索引 int ,varchar(10), char(5)
避免 ,>= , % ,between 之前的條件。選擇索引的字段的范圍和模糊之前,因為范圍與模糊會引起索引失效,針對于聯合索引,就是聯合索引的中間盡量不要有范圍查詢的字段
盡量多使用explain分析
避免更新頻繁的字段 (二叉樹會一直變化,導致性能變慢)
建立的索引- 優先考慮 建立 聯合索引
索引字段不要有 null, 不是 ‘’
總結
以上是生活随笔為你收集整理的mysql5.5索引,MySQL--5索引选择原则的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 彻底关闭Win10自动更新的代码
- 下一篇: oracle 11g函数包缓存,Orac