Mysql index索引


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 | +----+-------------+----------+------------+-------+-----------------+-----------------+---------+------+------+----------+-----------------------+


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM