作為唯一索引_Mysql什么情況下不走索引?

本文基于Mysql5.7版本和InnoDB存儲引擎。

1、InnoDB索引組織表

在InnoDB引擎中,表都是按照主鍵順序組織存放的,這種存放方式的表稱為索引組織表。InnoDB存儲引擎中的表,都有主鍵,如果沒有顯式聲明主鍵,則采取以下措施:
  • 該表如果有非空唯一索引,則該列為主鍵;如果有多個,則取第一個;

  • 如果沒有非空唯一索引,則InnoDB自動創建一個大小為6字節的指針作為主鍵;

為什么推薦使用自增ID做主鍵而不是UUID?

  • 這是由于B+樹的性質決定的,UUID無序,占用空間大,每(磁盤)頁能存放的索引少,這會導致磁盤IO次數增加,效率變慢;

什么是堆表?

  • 與索引組織表相對應,堆表是按照行數據的插入順序存放,無組織,在某些情況下,堆表比索引組織表更快;

2、索引原理

2.1、什么是索引?

  • 索引是一個單獨的、存儲在磁盤上的數據庫結構。

  • InnoDB支持B+樹索引;B+樹索引由于一個結點存儲的是一個磁盤頁的數據,因此只能先找到被查找數據所在的頁,然后將頁讀進內存中,最后再在內存中查找;

  • 關于B+樹數據結構的相關知識請看 什么是B-樹、B樹、B+樹、B*樹?

2.2、B+樹索引分類

聚集(主鍵)索引

輔助(非聚集、二級)索引

  • 普通索引

  • 唯一索引

  • 聯合索引

聚集索引和主鍵索引的相同點:

  • 葉子結點存放所有數據(這是由B+樹的性質所決定的);

不同點:

  • 聚集索引的葉子結點存放一整行數據,而輔助索引的葉子結點只存放該列數據和主鍵;

每張表只能有一個聚集索引,如果是select *操作,則優化器更傾向于使用聚集索引,因為聚集索引能在B+樹的葉子結點上找到一整行的數據;聚集索引對于主鍵的排序和范圍查找非常快;如果采用輔助索引查找,比如:select * from user where name="張三",假設在輔助索引name上通過3次查找得到(name=張三,id=10),再在聚集索引上通過3次查找得到id為10的整行數據,因此一共進行了6次查找;因此直接查找聚集索引比查找輔助索引效率高:聚集索引的葉子結點包含了全部數據;

2.3、聯合索引原理

f2074ebd6a4dca9f53f040f52380c47f.png

如上圖所示,聯合索引的結點以(a列的值,b列的值)形式存儲。

下面看看如何使用聯合索引進行查詢:

  • select * from tb1 where a=? and b=?,走聯合索引,因為a和b在一起是排序的;

  • select * from tb1 where a=?,走聯合索引,因為單獨的a是排序的;

  • select * from tb1 where b=?,不走聯合索引,因為單獨的b不是排序的,如上圖,b的順序為1,2,1,4,1,2;

聯合索引的好處:

  • 首先,a列和b列都是排好序的;比如我要查詢用戶最近三次的購買記錄,可以使用user_id作為索引,也可以使用(user_id,buy_date)的聯合索引;如果使用user_id作為索引,則需要將查詢出來的結果再按buy_date進行一次排序,才能查出最近三次的購買記錄;而聯合索引已經將buy_date排好序了,只需要取最后三條數據,就是用戶最新三次的購買記錄;

2.4、什么是覆蓋索引?

定義:如果能直接從輔助索引上查找到所有想要的數據,而不需要回表(通過主鍵在聚集索引上做二次查詢),就稱該輔助索引覆蓋了這條select語句,又稱索引覆蓋;


優化器一般會傾向于使用覆蓋索引而不是聚集索引,因為聚集索引占用空間大,磁盤IO次數多;

聯合索引可以當做覆蓋索引使用。對于聯合索引(a,b)而言,使用b作為查詢條件則不走索引,但是如果此時沒有針對b的索引,且要查詢的列該聯合索引都有,則優化器會將該聯合索引視作覆蓋索引(聯合索引上單獨的b是無序的,所以是從頭到尾順序查找,盡管如此也比在聚集索引上順序查找效率高),explain的Extra中有Using index就表明使用了覆蓋索引;

2.5、操作索引

查看某個表的索引:show?index from?表名

下面解釋一下各字段的意思:

  • Table:索引所在表名;

  • Non_unique:值為0表示唯一;

  • Key_name:索引名稱;

  • Seq_in_index:索引中該列的位置;

  • Column:索引中列的名稱;

  • Collation:列以什么方式存儲在索引中,值為A或NULL,B+樹索引總是A,即排序的;

  • Cardinality:表示該列中唯一值數目的估計值。如果該值非常小,則表示該列重復數據較多;為什么是估計值呢?因為該值不是實時更新的(代價太大),可以用analyze table命令手動更新一次Cardinality值;

  • Sub_part:是否只對列的一部分索引;比如某個列類型為varchar(1000),可以設置只索引該列的前100個字符,則Sub_part的值為100,如果索引的是列的全部,則Sub_part為NULL;

  • Packed:關鍵字如何被壓縮。如果沒有被壓縮則為NULL;

  • Null:該列是否允許有NULL值;

  • Index_type:索引類型;

在select語句中使用force index(index_name)強制使用某個索引,而user index(index_name)則提示使用某個索引。

3、性能優化

3.1、執行計劃

查看sql的執行計劃:explain?select ...

下面簡要介紹一下各字段的意思,詳細解釋請查閱Mysql5.7官方文檔:https://dev.mysql.com/doc/refman/5.7/en/explain-output.html

id:select的查詢序列號

select_type:查詢類型

  • simple:簡單查詢,不包括連接查詢和子查詢

  • primary:主要的查詢,最外層的查詢

  • subquery:子查詢

table:表示查詢的表

partitions:命中的分區,如果是非分區表則為NULL

type:表的連接類型

  • const:只返回一行數據,查詢速度很快,該列具有唯一索引或主鍵索引;如果是普通索引,即時真的只返回一行數據,也不會是const;

  • range:范圍查詢;

  • index:根據輔助索引全表掃描;

  • ALL:無索引(聚集索引)全表掃描;

possible_keys:通過檢測where子句獲得可用的索引;

key:實際使用的索引;

rows:顯示Mysql在表中進行查詢時必須檢查的行數;

extra:表示Mysql在處理查詢時的詳細信息;

3.2、索引設計原則

索引優點:

  • 唯一索引可以保證唯一性;

  • 加快速度:查詢速度、表與表連接速度、分組和排序的速度;

缺點:

  • 索引需要占用磁盤空間;

  • 索引的維護(增刪改)需要時間,尤其是數據量大的時候;

索引設計原則:

  • 索引并非越多越好,索引太多會影響insert、update、delete的性能;

  • 經常更新的列不使用索引,經常查詢(邏輯外鍵、where子句、group by子句、order by子句)的列使用索引;

  • 數據量小的表不使用索引;

  • 重復值很多的列不使用索引;

  • 刪除長期未使用的索引,不用的索引會造成不必要的性能消耗;

  • 避免使用冗余索引:如(name,city)和(name)就是冗余索引,因此一般應該擴展已有的索引,而不是創建新的索引;

3.3、索引失效的情況

避免where子句中對字段施加函數,會造成無法命中索引。
  • 這是因為b+樹只能對原值進行索引。

索引列盡量不要存在null值,將該列設置not null約束,可以用0代替null。

假設訂單表有1000萬數據,訂單號為null有100條,分析如下三條sql語句:

explain?select?order_num from?goods_order where?order_num ='f035a84a-4672-4517-bd8a-2c9f2d92423e'
explain?select?order_num from?goods_order where?order_num is?null
explain?select?order_num from?goods_order where?order_num is?not?null

通過執行結果發現,只有is not null不走索引。

聯合索引遵循最左前綴原則,否則不走索引。

使用in不走索引,用exists代替,如果是連續的數值則可以用between代替。

應盡量避免在 where 子句中使用 or 來連接條件,如果一個字段有索引,一個字段沒有索引,則不走索引。like子句不能前置百分比,否則不走索引,如果非要前置百分比不可,則考慮使用全文索引。where 子句中不要使用 != 或 <> ,否則不走索引。limit offset查詢緩慢時,可以借助主鍵索引來提高性能:
  • select a.* from bigtable a inner join (select?id from bigtable LIMIT?6520000,10)?b on a.id=b.id

最后看一下下面這種情況:

比如select * from order where order_id>10000 and order_id<20000,注意order_id不是主鍵,此時有一個輔助索引order_id,由于該索引上不包含所有的字段(注意是select *),因此還要回表。通過order_id找到的對應主鍵是無序的,所以回表的過程是磁盤離散讀,而磁盤順序讀的速度是遠大于離散讀的(固態硬盤的隨機讀速度非常快),特別是數據量大的情況下差異更明顯,這時會優化器會放棄輔助索引而走全表掃描。

總體來說,優化器選擇走不走索引,也不是千篇一律的,有時候也要看實際情況。對于我們而言,要熟練使用explain查看sql執行計劃,在實際項目中分析sql性能的瓶頸,進行優化。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/383037.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383037.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383037.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python捕獲全局異常統一管理_python中如何用sys.excepthook來對全局異常進行捕獲、顯示及輸出到error日志中...

使用sys.excepthook函數進行全局異常的獲取。1. 使用MessageDialog實現異常顯示&#xff1b;2. 使用logger把捕獲的異常信息輸出到日志中&#xff1b;步驟&#xff1a;定義異常處理函數&#xff0c; 并使用該函來替換掉系統的內置處理函數&#xff1b;對于threading.py的異常捕…

r語言系統計算上是奇異的_R語言實現并行計算

Python作為多線程的編程語言在并行方面相對于R語言有很大的優勢&#xff0c;然而作為占據統計分析一席之地的R語言自然不能沒有并行計算的助力。那么我們來看下在R語言中有哪些并行的包&#xff1a;隱式并行&#xff1a;OpenBLAS&#xff0c;Intel MKL&#xff0c;NVIDIA cuBLA…

cansina 目錄_dirmap - 一個高級web目錄、文件掃描工具-華盟網

Dirmap一個高級web目錄掃描工具&#xff0c;功能將會強于DirBuster、Dirsearch、cansina、御劍需求分析經過大量調研&#xff0c;總結一個優秀的web目錄掃描工具至少具備以下功能&#xff1a;并發引擎能使用字典能純爆破能爬取頁面動態生成字典能fuzz掃描自定義請求自定義響應結…

唯有自己變得強大_物競天擇,適者生存,唯有強大自己,方能百毒不侵

物競天擇&#xff0c;適者生存&#xff0c;這是亙古不變的道理。面對生活中的困難&#xff0c;人生路上的挫折&#xff0c;我們只有足夠堅強&#xff0c;足夠勇敢&#xff0c;足夠強大&#xff0c;才能戰勝這一切。人活著要明白&#xff0c;你所有的負面&#xff0c;都源于你的…

樹莓派c語言運行_樹莓派完成簡單的編程(四)

在上一篇文章中&#xff0c;我們學習了Vi文本編輯器&#xff0c;那么用它可以實現什么功能呢&#xff1f;樹莓派python以及c語言編程這里我選擇了最簡單和很流行的兩種編程語言&#xff1a;C語言和Python。實現最簡單的功能&#xff0c;輸出hello world。Python編程簡介Python是…

mysql 讀寫引擎_揭秘MySQL存儲引擎spider

轉自&#xff1a;興趣部落?buluo.qq.com導讀&#xff1a; Spider是為MySQL/MariaDB開發的一個特殊引擎&#xff0c;具有內嵌分片功能。現在它已經被集成到MariaDB10.0及以上版本中&#xff0c;作為MariaDB的一個新的主要性。Spider的主要功能是將數據分散到多個后端節點&#…

python中的與或非_「Python基礎」 While 循環語句

Python 編程中 while 語句用于循環執行程序&#xff0c;即在某條件下&#xff0c;循環執行某段程序&#xff0c;以處理需要重復處理的相同任務。其基本形式為&#xff1a;while 判斷條件&#xff1a;執行語句……執行語句可以是單個語句或語句塊。判斷條件可以是任何表達式&…

lamp mysql大小限制_LAMP 調優之:MySQL 服務器調優

關于 MySQL 調優有 3 種方法可以加快 MySQL 服務器的運行速度&#xff0c;效率從低到高依次為&#xff1a;替換有問題的硬件。對 MySQL 進程的設置進行調優。對查詢進行優化。替換有問題的硬件通常是我們的第一考慮&#xff0c;主要原因是數據庫會占用大量資源。不過這種解決方…

go定時器 每天重復_Go語言學習基礎-定時器、計時器

Timer計時器如果希望在將來的某個時間點執行Go代碼&#xff0c;或者在某個時間間隔重復執行Go代碼&#xff0c;使用Go內置的timer和ticker功能。先看定時器timer&#xff0c;然后再看計時器ticker。定時器代表未來的單個事件。告訴定時器需要等待多長時間&#xff0c;它返回一個…

html類名定義規則_HTML入門筆記1

HTML 是誰發明的?Tim Berners-LeeHTML起手式&#xff1a;HTML起手式 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0&q…

mysql主從虛擬機_虛擬機centos7Mysql實現主從配置

環境搭建在虛擬機上和創建兩個一模一樣的centos7系統&#xff0c;并安裝相同版本的mysql(可以先創建一個再克隆)在master上操作登錄mysqlmysql -u root -p使用mysqluse mysql;創建用戶CREATE USER lystbc1% IDENTIFIED BY Lys135426tbc;給用戶授權GRANT REPLICATION SLAVE ON *…

怎樣檢測mysql5.5安裝成功_64位wiN7系統中裝配MySQL5.5.17(測試安裝成功哦!)

64位wiN7系統中安裝mysql5.5.17(測試安裝成功哦&#xff01;&#xff01;~~)下載地址&#xff1a;[url] http://www.mysql.com/downloads/mysql/[/url]下載的話需要登錄,你只需按照要求注冊一個賬號,然后下載即可.我下載的是mysql-5.5.17-winx64.msi版本.安裝步驟:Step 1. Mysq…

xcode 創建模擬器_Xcode編譯WebKit

下載WebKit源碼1)進入https://webkit.org/2)點擊頁面的 Get Started 進入新頁面&#xff0c;如下圖所示3)點擊 Getting the code 進入新頁面&#xff0c;如下圖所示4)在源碼下載頁面&#xff0c;有多種下載方式&#xff0c;包括直接下載代碼zip包&#xff0c;通過SVN下載&#…

mysql iscsi_iscsi共享存儲的簡單配置和應用

1、環境介紹SCSI(Small Computer System Interface)是塊數據傳輸協議&#xff0c;在存儲行業廣泛應用&#xff0c;是存儲設備最基本的標準協議。從根本上說&#xff0c;iSCSI協議是一種利用IP網絡來傳輸潛伏時間短的SCSI數據塊的方法&#xff0c;ISCSI使用以太網協議傳送SCSI命…

request mysql 接口_TP5接口開發

開啟debug調試模式(正式上線建議關閉)config.php// 應用調試模式app_debug > true,設置輸出類型index.phpnamespace app\index\controller;class Index{public function index(){$data [name > steven, age > 24];return json([code > 0, msg > 操作成功, data…

django和mysql寫注冊_Django電商項目---完成注冊頁面和用戶登錄

完成基本的創建項目、用戶注冊、登錄、注銷功能創建Django項目,創建df_user的App創建靜態文件夾static(跟manage.py保持在同一級別下)復制靜態文件(css images js)到static路徑下修改settings.py文件修改templates路徑修改數據庫新添加靜態文件加載路徑Pycharm連接mysql數據庫…

命令行進入指定目錄_VIM學習筆記 操作目錄(Manipulate Directory)

在目錄間移動使用以下命令&#xff0c;可以顯示當前所在的目錄&#xff1a;:pwd使用以下命令&#xff0c;在Linux下可以進入HOME目錄&#xff0c;而在Windows下則顯示當前所在目錄&#xff1a;:cd使用以下命令&#xff0c;可以進入指定的目錄&#xff1a;:cd D:tepm使用以下命令…

mysql cluster雙機_GitHub - sophys/mysqlha: 博客“Mysql-cluster數據庫集群雙機HA研究”測試代碼...

mysqlha本代碼是基于博客Mysql-cluster數據庫集群雙機HA研究所寫的。測試采用的是32位環境&#xff0c;linux環境為debian&#xff0c;如果是其他系列只需修改部分指令即可。mysql-cluster版本位&#xff1a;mysql-cluster-gpl-7.2.7-linux2.6-i686.tar.gz&#xff0c;可自行去…

mysql gtid基礎_MySQL 基礎知識梳理學習(四)----GTID

在日常運維中&#xff0c;GTID帶來的最方便的作用就是搭建和維護主從復制。GTID的主從模式代替了MySQL早期版本中利用二進制日志文件的名稱和日志位置的做法&#xff0c;使用GTID使操作和維護都變得更加簡潔和可高。1.GTID的優點(1)基于GTID搭建主從復制根據簡單。(2)可以確保每…

k8s pod MySQL環境變量_Kubernetes 配置Pod和容器(一)定義容器環境變量

此頁展示了如何給運行在Kubernetes Pod中的容器定義環境變量。開始之前必須有一個Kubernets集群&#xff0c;和一個能和集群溝通的kubectl命令行工具。如果你還沒有集群&#xff0c;你可以用Minikube建立一個集群。給容器定義環境變量當你建立了一個Pod,你可以給你運行在Pod中的…