自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

「MySQL系列」索引設(shè)計(jì)原則、索引失效場景、Limit 、Order By、Group By 等常見場景優(yōu)化

數(shù)據(jù)庫 MySQL
MySQL在存儲(chǔ)數(shù)據(jù)之外,數(shù)據(jù)庫系統(tǒng)還維護(hù)者滿足特定查找算法的 數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)以某種方式引用(指向)數(shù)據(jù), 這樣就 可以在這些數(shù)據(jù)結(jié)構(gòu)上實(shí)現(xiàn)高級(jí)查找算法,這種數(shù)據(jù)結(jié)構(gòu)就是索引。

 一 索引使用

1.1 概述

1. 定義

索引幫助MySQL高效獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)(按照一定規(guī)則)。

2. 定義解釋

MySQL在存儲(chǔ)數(shù)據(jù)之外,數(shù)據(jù)庫系統(tǒng)還維護(hù)者滿足特定查找算法的 數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)以某種方式引用(指向)數(shù)據(jù), 這樣就 可以在這些數(shù)據(jù)結(jié)構(gòu)上實(shí)現(xiàn)高級(jí)查找算法,這種數(shù)據(jù)結(jié)構(gòu)就是索引。

3. 優(yōu)缺點(diǎn)

優(yōu)點(diǎn) 提高數(shù)據(jù)檢索效率,降低數(shù)據(jù)庫IO成本。通過索引對(duì)數(shù)據(jù)進(jìn)行排序降低數(shù)據(jù)排序成本,降低CPU消耗。缺點(diǎn) 實(shí)際上索引也是一張表,該表中保存了主鍵與索引字段,并指向?qū)嶓w類的記錄,所以索引列也是要占用空間的。更新表時(shí),MySQL 不僅要保存數(shù)據(jù),還要保存一下索引文件每次更新添加了索引列的字段,都會(huì)調(diào)整因?yàn)楦滤鶐淼逆I值變化后的索引信息。

1.2 索引結(jié)構(gòu)(InnoDB)

MySQL數(shù)據(jù)庫中默認(rèn)的存儲(chǔ)引擎InnoDB的索引結(jié)構(gòu)為B+樹,而根據(jù) 葉子節(jié)點(diǎn)的內(nèi)存存儲(chǔ)不同,索引類型分為主鍵索引和非主鍵索引。

1. 主鍵索引(聚簇索引)

主鍵索引的葉子節(jié)點(diǎn)存儲(chǔ)的是整行數(shù)據(jù),其結(jié)構(gòu)如下:


2. 非主鍵索引(二級(jí)索引或輔助索引)

而非主鍵索引的葉子節(jié)點(diǎn)內(nèi)容存儲(chǔ)時(shí)的主鍵的值,其結(jié)構(gòu)如下: 

1.3 索引使用規(guī)則

沒有建立索引,執(zhí)行計(jì)劃如下


建立索引

  1. create index idx_seller_name_status_address on tb_seller(name, status, seller); 

1. 全值匹配,對(duì)索引所有列都制定具體值

  1. explain select * from tb_seller where name='小米科技' and status='1' and 
  2. address='北京市'

 

2. 最左前綴法制


違背最左法則,索引失效


如果符合最左法則,但是出現(xiàn)跳躍某一列,只有最左列索引生效:


3. 范圍查詢右邊的列,不能使用索引


根據(jù)前面的兩個(gè)字段name,status查詢是走索引的,但是最后一 個(gè)條件address 沒有用到索引。

4. 索引列上進(jìn)行運(yùn)算操作,索引失效


5. 字符串不加單引號(hào),造成索引失效


由于,在查詢是,沒有對(duì)字符串加單引號(hào),MySQL的查詢優(yōu)化器, 會(huì)自動(dòng)的進(jìn)行類型轉(zhuǎn)換,造成索引失效。

6. 用or分割開的條件

示例,name字段是索引列 , 而createtime不是索引列,中間是 or進(jìn)行連接是不走索引的 :

  1. explain select * from tb_seller where name='黑馬程序員' or createtime = '2088-01-01 12:00:00'\G; 

 

7. 以%開頭的Like模糊查詢,索引失效。


解決方案


8. 如果MySQL評(píng)估使用索引比全表更慢,則不使用索引


9. is NULL,is NOT NULL有時(shí)索引失效。


10. in,not in有時(shí)索引失效


11. 盡量使用覆蓋索引,避免select

盡量使用覆蓋索引(只訪問索引的查詢(索引列完全包含查詢列)),減少select。


如果查詢列,超出索引列,也會(huì)降低性能。

  1. using index :使用覆蓋索引的時(shí)候就會(huì)出現(xiàn) 
  2. using where:在查找使用索引的情況下,需要回表去查詢所需的數(shù)據(jù) 
  3. using index condition:查找使用了索引,但是需要回表查詢數(shù)據(jù) 
  4. using index ; using where:查找使用了索引,但是需要的數(shù)據(jù)都在索引列中能找到,所以不需要 
  5. 回表查詢數(shù)據(jù) 

1.4 索引設(shè)計(jì)原則

索引的設(shè)計(jì)可以遵循一些已有的原則,創(chuàng)建索引的時(shí)候請(qǐng)盡量考 慮符合這些原則,便于提升索引的使用效率,更高效的使用索引。

  1. 對(duì)查詢頻次較高,且數(shù)據(jù)量比較大的表建立索引。 
  2.  
  3. 索引字段的選擇,最佳候選列應(yīng)當(dāng)從where子句的條件中提取,如 
  4. where子句中的組合比較多,那么應(yīng)當(dāng)挑選最常用、過濾效果最 
  5. 好的列的組合。 
  6.  
  7. 使用唯一索引,區(qū)分度越高,使用索引的效率越高。 
  8.  
  9. 索引可以有效的提升查詢數(shù)據(jù)的效率,但索引數(shù)量不是多多益 
  10. 善,索引越多,維護(hù)索引的代價(jià)自然也就水漲船高。對(duì)于插入、 
  11. 更新、刪除等DML操作比較頻繁的表來說,索引過多,會(huì)引入相當(dāng) 
  12. 高的維護(hù)代價(jià),降低DML操作的效率,增加相應(yīng)操作的時(shí)間消耗。 
  13. 另外索引過多的話,MySQL也會(huì)犯選擇困難病,雖然最終仍然會(huì)找 
  14. 到一個(gè)可用的索引,但無疑提高了選擇的代價(jià)。 
  15.  
  16. 使用短索引,索引創(chuàng)建之后也是使用硬盤來存儲(chǔ)的,因此提升索 
  17. 引訪問的I/O效率,也可以提升總體的訪問效率。假如構(gòu)成索引的 
  18. 字段總長度比較短,那么在給定大小的存儲(chǔ)塊內(nèi)可以存儲(chǔ)更多的 
  19. 索引值,相應(yīng)的可以有效的提升MySQL訪問索引的I/O效率。 
  20.  
  21. 利用最左前綴,N個(gè)列組合而成的組合索引,那么相當(dāng)于是創(chuàng)建了 
  22. N個(gè)索引,如果查詢時(shí)where子句中使用了組成該索引的前幾個(gè)字 
  23. 段,那么這條查詢SQL可以利用組合索引來提升查詢效率。 

二 常見SQL優(yōu)化

2.1 數(shù)據(jù)庫準(zhǔn)備

1. sql

  1. CREATE TABLE `emp` ( 
  2.   `id` int(11) NOT NULL AUTO_INCREMENT, 
  3.   `namevarchar(100) NOT NULL
  4.   `age` int(3) NOT NULL
  5.   `salary` int(11) DEFAULT NULL
  6.   PRIMARY KEY (`id`) 
  7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; 
  8. insert into `emp` (`id`, `name`, `age`, `salary`) values('1','Tom','25','2300'); 
  9. insert into `emp` (`id`, `name`, `age`, `salary`) 
  10. values('2','Jerry','30','3500'); 
  11. insert into `emp` (`id`, `name`, `age`, `salary`) 
  12. values('3','Luci','25','2800'); 
  13. insert into `emp` (`id`, `name`, `age`, `salary`) values('4','Jay','36','3500'); 
  14. insert into `emp` (`id`, `name`, `age`, `salary`) 
  15. values('5','Tom2','21','2200'); 
  16. insert into `emp` (`id`, `name`, `age`, `salary`) 
  17. values('6','Jerry2','31','3300'); 
  18. insert into `emp` (`id`, `name`, `age`, `salary`) 
  19. values('7','Luci2','26','2700'); 
  20. insert into `emp` (`id`, `name`, `age`, `salary`) 
  21. values('8','Jay2','33','3500'); 
  22. insert into `emp` (`id`, `name`, `age`, `salary`) 
  23. values('9','Tom3','23','2400'); 
  24. insert into `emp` (`id`, `name`, `age`, `salary`) 
  25. values('10','Jerry3','32','3100'); 
  26. insert into `emp` (`id`, `name`, `age`, `salary`) 
  27. values('11','Luci3','26','2900'); 
  28. insert into `emp` (`id`, `name`, `age`, `salary`) 
  29. values('12','Jay3','37','4500'); 
  30. create index idx_emp_age_salary on emp(age,salary); 

2.2 order by優(yōu)化

1. filesort 排序

第一種是通過對(duì)返回?cái)?shù)據(jù)進(jìn)行排序,也就是通常說的 filesort排 序,所有不是通過索引直接返回排序結(jié)果的排序都叫 FileSort排 序。


2. using index

第二種通過有序索引順序掃描直接返回有序數(shù)據(jù),這種情況即為 using index,不需要額外排序,操作效率高。


多字段排序

了解了MySQL的排序方式,優(yōu)化目標(biāo)就清晰了:盡量減少額外的排 序,通過索引直接返回有序數(shù)據(jù)。where 條件和Order by 使用 相同的索引,并且Order By 的順序和索引順序相同, 并且 Order by 的字段都是升序,或者都是降序。否則肯定需要額外的 操作,這樣就會(huì)出現(xiàn)FileSort。

3. 對(duì)上面兩種進(jìn)行優(yōu)化

通過創(chuàng)建合適的索引,能夠減少 Filesort 的出現(xiàn),但是在某些 情況下,條件限制不能讓Filesort消失,那就需要加快Filesort 的排序操作。對(duì)于Filesort , MySQL 現(xiàn)在采用的是一次掃描算 法:一次性取出滿足條件的所有字段,然后在排序區(qū) sortbuffer 中排序后直接輸出結(jié)果集。排序時(shí)內(nèi)存開銷較大,但是排序效率 比兩次掃描算法要高。

MySQL 通過比較系統(tǒng)變量 max_length_for_sort_data 的大小 和Query語句取出的字段總大小, 來判定是否那種排序算法,如 果max_length_for_sort_data 更大,那么使用第二種優(yōu)化之后 的算法;否則使用第一種。

可以適當(dāng)提高 sort_buffer_size max_length_for_sort_data 系統(tǒng)變量,來增大排序區(qū)的大小,提高排序的效率。

2.3 group by優(yōu)化

由于GROUP BY 實(shí)際上也同樣會(huì)進(jìn)行排序操作,而且與ORDER BY 相比,GROUP BY 主要只是多了排序之后的分組操作。當(dāng)然,如果 在分組的時(shí)候還使用了其他的一些聚合函數(shù),那么還需要一些聚 合函數(shù)的計(jì)算。所以,在GROUP BY 的實(shí)現(xiàn)過程中,與 ORDER BY 一樣也可以利用到索引。

如果查詢包含 group by 但是用戶想要避免排序結(jié)果的消耗, 則 可以執(zhí)行order by null 禁止排序。如下 :

  1. drop index idx_emp_age_salary on emp; 
  2. explain select age,count(*) from emp group by age; 

 

優(yōu)化后

  1. explain select age,count(*) from emp group by age order by null

 

從上面的例子可以看出,第一個(gè)SQL語句需要進(jìn)行"filesort",而 第二個(gè)SQL由于order by null 不需要進(jìn)行 "filesort", 而上 文提過Filesort往往非常耗費(fèi)時(shí)間。

創(chuàng)建索引

  1. create index idx_emp_age_salary on emp(age,salary); 

 

2.4 limit優(yōu)化

一般分頁查詢時(shí),通過創(chuàng)建覆蓋索引能夠比較好地提高性能。一 個(gè)常見又非常頭疼的問題就是 limit5000000,10 ,此時(shí)需要 MySQL排序前5000010 記錄,僅僅返回5000000 - 5000010 的記 錄,其他記錄丟棄,查詢排序的代價(jià)非常大 。

limit分頁操作, 越往后, 性能越低 :


優(yōu)化方案

  1. select * from tb_sku t , (select id from tb_sku order by id limit 9000000,1) a where t.id = a.id; 

 

2.5 count優(yōu)化

在很多的業(yè)務(wù)系統(tǒng)中,都需要考慮進(jìn)行分頁操作,但是當(dāng)我們執(zhí) 行分頁操作時(shí),都需要進(jìn)行一次count操作,求取總記錄數(shù),如果 數(shù)據(jù)庫表的數(shù)據(jù)量大,在InnoDB引擎中,執(zhí)行count操作的性能是 比較低的,需要遍歷全表數(shù)據(jù),對(duì)計(jì)數(shù)進(jìn)行累加。

優(yōu)化方案

  1. ①. 在大數(shù)據(jù)量的查詢中,只查詢數(shù)據(jù),而不展示總記錄數(shù) ; 
  2. ②. 通過緩存redis維護(hù)一個(gè)表的計(jì)數(shù),來記錄數(shù)據(jù)庫表的總記錄數(shù),在執(zhí)行插入/刪除時(shí),需要?jiǎng)討B(tài)更新; 
  3. ③. 在數(shù)據(jù)庫表中定義一個(gè)大數(shù)據(jù)量的計(jì)數(shù)表,在執(zhí)行插入/刪除時(shí),需要?jiǎng)討B(tài)更新。 

2.6 大批量插入優(yōu)化

1. 環(huán)境準(zhǔn)備

  1. CREATE TABLE `tb_user` ( 
  2.   `id` INT(11) NOT NULL AUTO_INCREMENT, 
  3.   `username` VARCHAR(50) NOT NULL
  4.   `passwordVARCHAR(50) NOT NULL
  5.   `nameVARCHAR(20) NOT NULL
  6.   `birthday` DATE DEFAULT NULL
  7.   `sex` CHAR(1) DEFAULT NULL
  8.   PRIMARY KEY (`id`), 
  9.   UNIQUE KEY `unique_user_username` (`username`) 
  10. ) ENGINE=INNODB DEFAULT CHARSET=utf8 ; 

當(dāng)使用 load 命令導(dǎo)入數(shù)據(jù)的時(shí)候,適當(dāng)?shù)脑O(shè)置可以提高導(dǎo)入的效率。

對(duì)于InnoDB 類型的表,有以下幾種方式可以提高導(dǎo)入的效率:

主鍵順序插入

因?yàn)镮nnoDB類型的表是按照主鍵的順序保存的,所以將導(dǎo)入的數(shù) 據(jù)按照主鍵的順序排列,可以有效的提高導(dǎo)入數(shù)據(jù)的效率。如果 InnoDB表沒有主鍵,那么系統(tǒng)會(huì)自動(dòng)默認(rèn)創(chuàng)建一個(gè)內(nèi)部列作為主 鍵,所以如果可以給表創(chuàng)建一個(gè)主鍵,將可以利用這點(diǎn),來提高 導(dǎo)入數(shù)據(jù)的效率。

  1. 腳本文件介紹 : 
  2.   sql1.log ----> 主鍵有序 
  3.   sql2.log ----> 主鍵無序 

插入ID順序排列數(shù)據(jù):

  1. load data local infile '/root/sql1.log' into table `tb_user` fields terminated by ',' lines terminated by '\n'

 

 插入ID無序排列數(shù)據(jù):

關(guān)閉唯一性校驗(yàn)

在導(dǎo)入數(shù)據(jù)前執(zhí)行 SET UNIQUE_CHECKS=0,關(guān)閉唯一性校驗(yàn),在 導(dǎo)入結(jié)束后執(zhí)行 SET UNIQUE_CHECKS=1,恢復(fù)唯一性校驗(yàn),可以 提高導(dǎo)入的效率。


手動(dòng)提交事務(wù)

如果應(yīng)用使用自動(dòng)提交的方式,建議在導(dǎo)入前執(zhí)行 SET AUTOCOMMIT=0,關(guān)閉自動(dòng)提交,導(dǎo)入結(jié)束后再執(zhí)行 SET AUTOCOMMIT=1,打開自動(dòng)提交,也可以提高導(dǎo)入的效率。


 

責(zé)任編輯:姜華 來源: 花花與Java
相關(guān)推薦

2024-05-08 08:18:05

索引失效場景

2022-05-26 08:23:05

MySQL索引數(shù)據(jù)庫

2024-04-19 13:57:30

索引數(shù)據(jù)庫查詢

2024-01-05 14:20:55

MySQL索引優(yōu)化器

2020-10-19 19:45:58

MySQL數(shù)據(jù)庫優(yōu)化

2020-07-16 21:20:08

數(shù)據(jù)庫MySQL死鎖

2020-12-08 09:45:07

MySQL數(shù)據(jù)庫索引

2022-02-28 08:55:31

數(shù)據(jù)庫MySQL索引

2022-01-09 18:32:03

MySQL SQL 語句數(shù)據(jù)庫

2024-12-11 08:09:54

2021-10-12 08:43:19

Cobar分庫場景

2015-05-20 13:48:26

MySQL索引

2019-08-16 01:58:01

MySQL索引事務(wù)

2024-10-09 23:32:50

2023-05-23 22:19:04

索引MySQL優(yōu)化

2021-05-10 11:15:28

面試索引MySQL

2019-12-18 08:00:09

MySQL數(shù)據(jù)庫ORDER BY

2022-04-26 08:51:29

MySQLgroup by

2010-10-27 13:47:50

Oracle索引

2024-04-17 12:58:15

MySQL索引數(shù)據(jù)庫
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)