性能優(yōu)化

MySQL中使用索引的典型場(chǎng)景

  • 匹配全值
    對(duì)索引所有列都指定具體值,即是對(duì)索引中的所有列都有等值匹配的條件。

如我們有以下表結(jié)構(gòu):

mysql> show create table rental\G;
*************************** 1. row ***************************
  Table: rental
  Create Table: CREATE TABLE `rental` (
  `rental_id` int NOT NULL AUTO_INCREMENT,
  `rental_date` datetime NOT NULL,
  `inventory_id` mediumint unsigned NOT NULL,
  `customer_id` smallint unsigned NOT NULL,
  `return_date` datetime DEFAULT NULL,
  `staff_id` tinyint unsigned NOT NULL,
  `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`rental_id`),
  UNIQUE KEY `rental_date` (`rental_date`,`inventory_id`,`customer_id`),
  KEY `idx_fk_inventory_id` (`inventory_id`),
  KEY `idx_fk_customer_id` (`customer_id`),
  KEY `idx_fk_staff_id` (`staff_id`),
  CONSTRAINT `fk_rental_customer` FOREIGN KEY (`customer_id`) REFERENCES `customer` (`customer_id`) ON DELETE RESTRICT ON UPDATE CASCADE,
  CONSTRAINT `fk_rental_inventory` FOREIGN KEY (`inventory_id`) REFERENCES `inventory` (`inventory_id`) ON DELETE RESTRICT ON UPDATE CASCADE,
  CONSTRAINT `fk_rental_staff` FOREIGN KEY (`staff_id`) REFERENCES `staff` (`staff_id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=16050 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

mysql> show create table payment\G;
*************************** 1. row ***************************
       Table: payment
Create Table: CREATE TABLE `payment` (
  `payment_id` smallint unsigned NOT NULL AUTO_INCREMENT,
  `customer_id` smallint unsigned NOT NULL,
  `staff_id` tinyint unsigned NOT NULL,
  `rental_id` int DEFAULT NULL,
  `amount` decimal(5,2) NOT NULL,
  `payment_date` datetime NOT NULL,
  `last_update` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`payment_id`),
  KEY `idx_fk_staff_id` (`staff_id`),
  KEY `idx_fk_customer_id` (`customer_id`),
  KEY `fk_payment_rental` (`rental_id`),
  KEY `idx_payment_date` (`payment_date`,`amount`,`last_update`),
  CONSTRAINT `fk_payment_customer` FOREIGN KEY (`customer_id`) REFERENCES `customer` (`customer_id`) ON DELETE RESTRICT ON UPDATE CASCADE,
  CONSTRAINT `fk_payment_rental` FOREIGN KEY (`rental_id`) REFERENCES `rental` (`rental_id`) ON DELETE SET NULL ON UPDATE CASCADE,
  CONSTRAINT `fk_payment_staff` FOREIGN KEY (`staff_id`) REFERENCES `staff` (`staff_id`) ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=16050 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

當(dāng)我們執(zhí)行以下sql語(yǔ)句:

mysql> explain select * from rental where rental_date="2005-05-25 17:22:10" and inventory_id=373 and customer_id=343\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: rental
   partitions: NULL
         type: const
possible_keys: rental_date,idx_fk_inventory_id,idx_fk_customer_id
          key: rental_date
      key_len: 10
          ref: const,const,const
         rows: 1
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)

字段key的值為rental_date,表示優(yōu)化器選擇索引rental_date進(jìn)行掃描。

  • 匹配值的范圍查詢
    對(duì)索引的值能夠進(jìn)行范圍查詢。
    如檢索租賃表 rental 中客戶編號(hào)customer_id在指定范圍內(nèi)的記錄:
mysql> explain select * from rental where customer_id>= 373 and customer_id < 400\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: rental
   partitions: NULL
         type: range
possible_keys: idx_fk_customer_id
          key: idx_fk_customer_id
      key_len: 2
          ref: NULL
         rows: 718
     filtered: 100.00
        Extra: Using index condition
1 row in set, 1 warning (0.00 sec)

Extra: Using index condition 表示MySQL使用了ICP來(lái)進(jìn)一步優(yōu)化查詢,在檢索的時(shí)候,把條件customer_id的過(guò)濾操作下推到存儲(chǔ)引擎層來(lái)完成,這樣可以降低不必要的IO訪問(wèn)。

  • 匹配最左前綴
    僅僅使用索引中的最左邊列進(jìn)行查找,比如在col1+col2+col3字段上的聯(lián)合索引能夠被包含col1(col1+col2)、(col1+col2+col3)的等值查詢利用到,可是不能被col2、(col2+col3)的等值查詢利用到。

  • 僅僅對(duì)索引進(jìn)行查詢,當(dāng)查詢的列都在索引的字段上時(shí),查詢的效率更高。

mysql> explain select last_update from payment where payment_date='2006-02-14 15:16:03' and amount=3.98\G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: payment
   partitions: NULL
         type: ref
possible_keys: idx_payment_date
          key: idx_payment_date
      key_len: 8
          ref: const,const
         rows: 8
     filtered: 100.00
        Extra: Using index
1 row in set, 1 warning (0.00 sec)

Extra部分變成了Using index,也就意味著,現(xiàn)在直接訪問(wèn)索引就足夠獲取到所需要的數(shù)據(jù),不需要通過(guò)索引回表,Using index也就是平常說(shuō)的覆蓋索引掃描。只訪問(wèn)必須訪問(wèn)的數(shù)據(jù),在一般情況下,減少不必要的數(shù)據(jù)訪問(wèn)能提高效率。

如何計(jì)算 key_len 列的值?

這一列顯示了mysql在索引里使用的字節(jié)數(shù),通過(guò)這個(gè)值可以算出具體使用了索引中的哪些列。

ken_len計(jì)算規(guī)則如下:

數(shù)據(jù)類型 含義
char(n) n字節(jié)長(zhǎng)度
varchar(n) 使用2字節(jié)存儲(chǔ)字符串長(zhǎng)度,如果是utf-8,則長(zhǎng)度 3n + 2
tinyint 1字節(jié)
smallint 2字節(jié)
int 4字節(jié)
bigint 8字節(jié)
date 3字節(jié)
timestamp 4字節(jié)
datetime 8字節(jié)
  • 如果字段允許為 NULL,需要1字節(jié)記錄是否為 NULL 索引最大長(zhǎng)度是768字節(jié),當(dāng)字符串過(guò)長(zhǎng)時(shí),mysql會(huì)做一個(gè)類似左前綴索引的處理,將前半部分的字符提取出來(lái)做索引。
如何理解ICP特性(索引下推)。

MySQL 5.6 引入了Index Condition Pushdown (ICP)的特性,進(jìn)一步優(yōu)化了查詢。PushDown 表示操作下放,某些情況下的條件過(guò)濾操作下放到存儲(chǔ)引擎。

如執(zhí)行以下sql語(yǔ)句,其內(nèi)部執(zhí)行流程如圖所示:

mysql> explain select * from rental where rental_date='2006-02-14 15:16:03' and customer_id >= 300 and customer_id <= 400 \G;
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: rental
   partitions: NULL
         type: ref
possible_keys: rental_date,idx_fk_customer_id
          key: rental_date
      key_len: 5
          ref: const
         rows: 182
     filtered: 16.85
        Extra: Using index condition
1 row in set, 1 warning (0.00 sec)

尚未使用ICP特性
使用ICP特性

深入淺出索引
索引與Index Condition Pushdown
參考鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • MySQL 性能優(yōu)化 1. 靈魂拷問(wèn) MySQL的索引在執(zhí)行過(guò)程中是如何被使用的? MySQL的表數(shù)據(jù)和索引在底層...
    二俊_5254閱讀 352評(píng)論 0 0
  • 原作者 https://smartan123.github.io/book/?file=home-%E9%A6%9...
    還有點(diǎn)頭發(fā)閱讀 677評(píng)論 0 0
  • 轉(zhuǎn) # https://www.cnblogs.com/easypass/archive/2010/12/ 08/...
    呂品?閱讀 10,123評(píng)論 0 44
  • 國(guó)慶第二天,今天嗨翻模式的開(kāi)啟就等室友的同學(xué)來(lái)了再說(shuō)吧,在這之前,先來(lái)一波筆記 查詢真正重要的是響應(yīng)時(shí)間,查詢包含...
    小煉君閱讀 1,821評(píng)論 0 50
  • 1. 為什么查詢速度慢 一個(gè)查詢是由許多子任務(wù)組成的,每個(gè)子任務(wù)都會(huì)消耗一定的時(shí)間。優(yōu)化一個(gè)查詢,其實(shí)就是要優(yōu)化其...
    Karl90閱讀 485評(píng)論 0 0

友情鏈接更多精彩內(nèi)容