mysql優化-合理利用索引

1.索引的簡介

正確合理的利用索引是提升數據庫查詢性能的方式之一,索引就想目錄一樣,能幫我們快速的定位數據,mysql索引種類有B樹索引,hash索引,全文索引,空間索引等。一般我們只重點關注B樹索引。
一般從幾個方面評價索引的優劣,
1星索引:可以通過索引掃描數據
2星索引:在1星的基礎上,可以使用覆蓋索引,無需再回表查詢
3星索引:在二星的基礎上,可以利用索引完成排序。
mysql索引的原理:點擊查看,我們這裏不再複述。
https://blog.csdn.net/lucky_ly/category_7563195.html

2.索引的創建

先看索引的sql定義語句如下,可以在表定義時,創建也可以在後來手動添加。

2.1 創建表時指定索引

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
    (create_definition,...)
    [table_options]
    [partition_options]

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
    [(create_definition,...)]
    [table_options]
    [partition_options]
    [IGNORE | REPLACE]
    [AS] query_expression

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
    { LIKE old_tbl_name | (LIKE old_tbl_name) }

create_definition:
    col_name column_definition
  | {INDEX|KEY} [index_name] [index_type] (key_part,...)
      [index_option] ...
  | {FULLTEXT|SPATIAL} [INDEX|KEY] [index_name] (key_part,...)
      [index_option] ...
  | [CONSTRAINT [symbol]] PRIMARY KEY
      [index_type] (key_part,...)
      [index_option] ...
  | [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY]
      [index_name] [index_type] (key_part,...)
      [index_option] ...
  | [CONSTRAINT [symbol]] FOREIGN KEY
      [index_name] (col_name,...)
      reference_definition
  | CHECK (expr)

示例如下:

CREATE TABLE `film` (
  `film_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `description` text,
  `release_year` year(4) DEFAULT NULL,
  `language_id` tinyint(3) unsigned NOT NULL,
  `original_language_id` tinyint(3) unsigned DEFAULT NULL,
  `rental_duration` tinyint(3) unsigned NOT NULL DEFAULT '3',
  `rental_rate` decimal(4,2) NOT NULL DEFAULT '4.99',
  `length` smallint(5) unsigned DEFAULT NULL,
  `replacement_cost` decimal(5,2) NOT NULL DEFAULT '19.99',
  `rating` enum('G','PG','PG-13','R','NC-17') DEFAULT 'G',
  `special_features` set('Trailers','Commentaries','Deleted Scenes','Behind the Scenes') DEFAULT NULL,
  `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`film_id`),
  KEY `idx_title` (`title`),
  KEY `idx_fk_language_id` (`language_id`),
  KEY `idx_fk_original_language_id` (`original_language_id`),
  KEY `idx_film_length` (`length`),
  CONSTRAINT `fk_film_language` FOREIGN KEY (`language_id`) REFERENCES `language` (`language_id`) ON DELETE RESTRICT ON UPDATE CASCADE,
  CONSTRAINT `fk_film_language_original` FOREIGN KEY (`original_language_id`) REFERENCES `language` (`language_id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8;

key和index都可以定義索引,index_type可選btree和hash索引,默認是Btree索引,

2.2 直接創建索引

CREATE [UNIQUE | FULLTEXT | SPATIAL] INDEX index_name
    [index_type]
    ON tbl_name (key_part,...)
    [index_option]
    [algorithm_option | lock_option] ...

key_part:
    col_name [(length)] [ASC | DESC]

index_option:
    KEY_BLOCK_SIZE [=] value
  | index_type
  | WITH PARSER parser_name
  | COMMENT 'string'

index_type:
    USING {BTREE | HASH}

algorithm_option:
    ALGORITHM [=] {DEFAULT | INPLACE | COPY}

lock_option:
    LOCK [=] {DEFAULT | NONE | SHARED | EXCLUSIVE}

示例:

create index idx_film_length on film(length desc);

一般索引名以idx開頭,下劃線分割,然後解表名,和列名。

2.3 查看錶的索引信息:

show index from 表名
在這裏插入圖片描述

3. 索引優化

1 innodb會爲主鍵自動創建聚簇索引,主鍵最好選擇自增長id,或遞增的,有序的區分度較高的鍵。否則可能在插入數據時,會導致索引頻繁的裂變,如果鍵值有序的,數據可以直接追加在後頭,如果鍵無序,例如使用uuid當主鍵,要會先找到正確索引位置,在插入數據,中間會導致數據的移動,嚴重影響性能。而且會產生大量的碎片。
2. 在邏輯上符合的話,儘量創建唯一索引。
3. 表的連接列和一些區分度較高的where條件列可以創建索引。
4. 索引列不能用是表達式的一部分,不能是函數的參數,
5. like模糊匹配時,開頭不能是%,例如, select * from film where title like %toutiao%
6. 不要爲盲目的爲多個列創建單個索引,當有多個列時,可以創建多列索引,列的區分度儘量由高到低,多列索引的遵循最左匹配原則。
例如有學生表如下

CREATE TABLE `student` (
 `s_id` int(11) NOT NULL AUTO_INCREMENT,
 `sno` int(11) DEFAULT NULL,
 `sname` varchar(50) DEFAULT NULL,
 `age` int(11) DEFAULT NULL,
 `sex` char(1) DEFAULT NULL,
 `remark` varchar(500) DEFAULT NULL,
 PRIMARY KEY (`s_id`),
 UNIQUE KEY `uk_sno` (`sno`)
) ENGINE=InnoDB AUTO_INCREMENT=1DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

如果我們需要根據sname,age,sex條件去查詢,我們可以在此基礎上創建一個多列索引。

create index idx_student_sname_age_sex on student(sname,age,sex);

遵循最左匹配原則
1.使用左側第一列可以走索引
在這裏插入圖片描述
2.使用左側第一列和左側第二列也可以使用索引
在這裏插入圖片描述
3.使用第二列或第三列,即時在數據區分度很高的情況下,也只能走全表掃描

在這裏插入圖片描述
7.當爲字符類型的字段建立索引時,如果區分度合適的情況下,可以創建前綴索引,這樣可以減少索引佔用的空間,但是創建了前綴索引,就無法使用覆蓋索引了,使用時需要權衡利弊。
前綴索引的創建方式
如下爲sname創建一個前綴索引,保留前綴5個字符,

create index idx_student_sname on student(sname(5));

如何知道多少個保留多少個字符,區分度才較爲合適呢,我們比較該字段去重之後佔總數據的百分比和保留n個字符前綴佔總數據的百分比,
如下,保留到10字符時,比值和原來相等,基本就可以了。
對於text,blob數據類型,如果使用b-tree索引的話,必須指定前綴索引,對於唯一索引來所,前綴索引可能會引起報錯,因爲保留前綴可能無法區別唯一性。
在這裏插入圖片描述
8.利用索引字段的有序性,避免排序。這可以極大的提高性能。
對於多個排序字段排序時,如果要在這些字段上有組合索引也要遵循最左匹配原則,
例如,我們有一張學生表,有(birth_date,age,sex)組合索引

select * from student where birth_date = '2020-01-05' 
order by age,sex

前導列出現在where條件,也可以利用索引排序。
9.避免多個索引列的範圍查詢,mysql無法同時利用2個索引列進行範圍查詢。

4.總結

正確的使用索引是提高數據庫的性能的方式之一,但是是否決定走索引還是走全表,還是由優化器決定的,現在的主流數據庫都是使用基於成本的優化器,理解數據庫的原理,才能寫出最優的sql。

發佈了114 篇原創文章 · 獲贊 21 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章