Mysql index索引
Mysql index使用了B tree算法來提高了數據庫的搜索能力。
關於B樹的知識可見 :平衡搜索樹-B樹
相關知識的學習途徑:
強大的mysql學習網站: https://www.mysqltutorial.org/mysql-index/
凡人求索(簡書)的一篇文章:https://www.jianshu.com/p/f588c41f1cb5
MySQL樣本數據庫下載(用於練習,導入.sql的方法見https://www.cnblogs.com/chentianwei/p/12142068.html)
備注:如果使用workbench,可以生成EER圖,查看各個表的關聯關系,或者從👆下載pdf.
導入.sql完成后,開始練習下面語句:
mysql> explain select employeeNumber, lastName, firstName from employees where jobTitle = "Sales Rep"; +----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | employees | NULL | ALL | NULL | NULL | NULL | NULL | 23 | 10.00 | Using where | +----+-------------+-----------+------------+------+---------------+------+---------+------+------+----------+-------------+
這時,查詢了23條語句, 而employees全表,也就23條語句,證明是全表掃描!
為字段jobTitle創建索引:
mysql> create index jobTitle on employees(jobTitle);
然后再查詢:
mysql> explain select employeeNumber ,lastName, firstName from employees
-> where jobTitle = "Sales Rep";
+----+-------------+-----------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| 1 | SIMPLE | employees | NULL | ref | jobTitle | jobTitle | 52 | const | 17 | 100.00 | NULL |
+----+-------------+-----------+------------+------+---------------+----------+---------+-------+------+----------+-------+
因為有了索引,where子句中的jobTitle就無需全表掃描了,只查看了17行。
查看索引
mysql> show indexes from employees;
⚠️可以加where子句進行查找比如where Non_unique = 0 +-----------+------------+------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression | +-----------+------------+------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+ | employees | 0 | PRIMARY | 1 | employeeNumber | A | 23 | NULL | NULL | | BTREE | | | YES | NULL | | employees | 1 | reportsTo | 1 | reportsTo | A | 7 | NULL | NULL | YES | BTREE | | | YES | NULL | | employees | 1 | officeCode | 1 | officeCode | A | 7 | NULL | NULL | | BTREE | | | YES | NULL | | employees | 1 | jobTitle | 1 | jobTitle | A | 7 | NULL | NULL | | BTREE | | | YES | NULL | +-----------+------------+------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
可以看到索引使用了B樹的算法。
- Non_unique: 0代表否,即這個列的每個值都是唯一的; 1代表是, 非唯一的。
- key_name: 索引名字。如果兩個列有同一個索引名字,表示這兩個列用一個聯合索引。
- Seq_in_index: 索引中的序列序號,從1開始。
- Cardinality: 基數(表示有多少數量,和順序無關),這里是對一列中的唯一值的估計值。如果這個值較高那么就適合使用索引。
- Null: 如果列含有Null,則Yes
- Index_type: 表示索引類型:BTree, RTree, Hash, FullText等。
- Expression: 索引使用表達式而不是列/列前置值。
刪除索引
drop index key_name ON table_name;
上面的employees刪除索引jobTitle:
mysql> drop index jobTitle on employees;
注意:如key_name是primary,就把主鍵刪除了。
唯一性索引
primary key索引可以強制索引為唯一索引。但一張表只能有一個主鍵。
如果想要為其他列添加唯一的索引,需要使用unique index
mysql> create unique index idx_name on employees (firstName, lastName); mysql> show indexes from employees where Non_unique = 0; +-----------+------------+----------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression | +-----------+------------+----------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+ | employees | 0 | PRIMARY | 1 | employeeNumber | A | 23 | NULL | NULL | | BTREE | | | YES | NULL | | employees | 0 | idx_name | 1 | firstName | A | 21 | NULL | NULL | | BTREE | | | YES | NULL | | employees | 0 | idx_name | 2 | lastName | A | 23 | NULL | NULL | | BTREE | | | YES | NULL | +-----------+------------+----------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
- Seq_in_index: 索引中的序列序號,從1開始。firstName是第一索引索引sqe_in_index是1。
或者使用(都可以創建unique key):
alter table employees add constraint idx_name unique key(firstName, lastName);
Prefix index 前綴索引
為一個列創建一個索引,Mysql使用Btree或hash算法。如果這個列的數據類型是字符串,那么索引會消耗大量磁盤空間,並且會潛在底降低插入insert操作的效率。
為了優化這個問題,我們可以使用Prefix index。這種優化其實就是規定一個字符串長度len,這個len會小於絕大部分列的字符串的長度,每個字符串的前len部分會被創建為索引值,這樣就會減少磁盤空間的消耗了。
這是一個技巧性的優化。
例子:使用products表
mysql> SELECT -> productName, -> buyPrice, -> msrp -> FROM -> products -> WHERE -> productName LIKE '1970%'; +----------------------------+----------+--------+ | productName | buyPrice | msrp | +----------------------------+----------+--------+ | 1970 Plymouth Hemi Cuda | 31.92 | 79.80 | | 1970 Triumph Spitfire | 91.92 | 143.62 | | 1970 Chevy Chevelle SS 454 | 49.24 | 73.49 | | 1970 Dodge Coronet | 32.37 | 57.80 | +----------------------------+----------+--------+
用explain分析一下:
mysql> explain SELECT productName, buyPrice, msrp FROM products WHERE productName LIKE '1970%'; +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | products | NULL | ALL | NULL | NULL | NULL | NULL | 110 | 11.11 | Using where | +----+-------------+----------+------------+------+---------------+------+---------+------+------+----------+-------------+
發現row是110行。mysql進行了全表掃描。
在實際工作中,如果對productName的查詢非常頻繁,那么就要給他加上一個索引了。
create index idx_productName on products(productName)
但是,因為它是字符串類型的列,我們可以優化一下:使用Prefix index。
方法:
1. 查看這個列創建時的長度:varchar(70)。
mysql> desc products; +--------------------+---------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------------------+---------------+------+-----+---------+-------+ | productCode | varchar(15) | NO | PRI | NULL | | | productName | varchar(70) | NO | | NULL | | | productLine | varchar(50) | NO | MUL | NULL | | | productScale | varchar(10) | NO | | NULL | | | productVendor | varchar(50) | NO | | NULL | | | productDescription | text | NO | | NULL | | | quantityInStock | smallint(6) | NO | | NULL | | | buyPrice | decimal(10,2) | NO | | NULL | | | MSRP | decimal(10,2) | NO | | NULL | | +--------------------+---------------+------+-----+---------+-------+
2. 估計一下,一般用多長的字符串,這里估計20,發現可以包括全部的110條記錄。
mysql> select count(distinct left(productName, 20)) from products; +---------------------------------------+ | count(distinct left(productName, 20)) | +---------------------------------------+ | 110 |
3. 所以使用len: 20。 ex
explain SELECT productName, buyPrice, msrp FROM products WHERE productName LIKE '1970%';
+----+-------------+----------+------------+-------+-----------------+-----------------+---------+------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+----------+------------+-------+-----------------+-----------------+---------+------+------+----------+-----------------------+ | 1 | SIMPLE | products | NULL | range | idx_productName | idx_productName | 72 | NULL | 4 | 100.00 | Using index condition | +----+-------------+----------+------------+-------+-----------------+-----------------+---------+------+------+----------+-----------------------+