高性能MySQL(3)——創建高性能索引

索引對于良好的性能非常關鍵。尤其是當表中的數據量越來越大時,索引對性能的影響愈發重要。

一、索引的類型

在MySQL中,索引是在存儲引擎層而不是服務器層實現的。所以沒用統一的索引標準,不同存儲引擎的索引工作方式并不相同。

1.1、B-Tree

B-Tree索引即使用B-Tree數據結構來存儲數據。B-Tree通常意味著所有值都是按順序存儲的,并且每個葉子頁到根的距離相同。存儲引擎已不同的方式來使用B-Tree索引,性能也各不相同。

可以使用B-Tree索引的查詢類型——全鍵值、鍵值范圍和鍵前綴查找。其中鍵前綴查找只適用于根據最左前綴查找。

1.2、哈希索引

哈希索引基于哈希表實現,只有精確匹配索引的所有列的查詢才有效。在MySQL中,只有Memory引擎顯示支持哈希索引,這也是Memory引擎的默認索引類型。

對于每一行數據,存儲引擎都會對所有的索引列計算一個哈希碼,如果多個列的哈希碼相同,索引會以鏈表的方式存放多個記錄指針到同一個哈希條目中。哈希索引將所有的哈希碼存儲在索引中,同時在哈希表中保存指向每個數據行的指針。

1.3、全文索引

全文索引是一種特殊類型的索引,它查找的是文本中的關鍵詞,而不是直接比較索引中 的值。全文搜索和其他幾類索引的匹配方式完全不一樣。它有許多需要注意的細節,如 停用詞、詞干和復數、布爾搜索等。全文索引更類似于搜索引擎做的事情,而不是簡單 的WHERE條件匹配。

在相同的列上同時創建全文索引和基于值的B-Tree索引不會有沖突,全文索引適用于 MATCH AGAINST操作,而不是普通的WHERE條件操作。

1.4、其他索引類別

還有很多第三方的存儲引擎使用不同類型的數據結構來存儲索引。例如TokuDB使用分 形樹索引(fractal tree index),這是一類較新開發的數據結構,既有B-Tree的很多優點, 也避免了 B.Tree的一些缺點。如果通讀完本章,可以看到很多關于InnoDB的主題,包 括聚簇索引、覆蓋索引等。多數情況下,針對InnoDB的討論也都適用于TokuDB。

二、索引的優點

索引可以讓服務器快速地定位到表的指定位置。但是這并不是索引的唯一作用,到目前 為止可以看到,根據創建索引的數據結構不同,索引也有一些其他的附加作用。總結下來索引的三大優點:

  • 索引大大減少了服務器需要掃描的數據量;
  • 索引可以幫助服務器避免排序和臨時表;
  • 索引可以將隨機I/O變為順序I/O。

索引是最好的解決方案嗎?

索引并不總是最好的工具。總的來說,只有當索引幫助存儲引擎快速查找到記錄帶 來的好處大于其帶來的額外工作時,索引才是有效的。對于非常小的表,大部分情 況下簡單的全表掃描更高效。對于中到大型的表,索引就非常有效。但對于特大型的表,建立和使用索引的代價將隨之增長。這種情況下,則需要一種技術可以直接區分出查詢需要的一組數據,而不是一條記錄一條記錄地匹配。

三、高性能的索引策略

3.1、獨立的列

索引列不能是表達式的一部分,也不能是函數的參數。

例如:SELECT actor_id FROM actor WHERE actor_id + 1 = 5;

或者:SELECT actor_id FROM actor WHERE f(actor_id) = 5;

3.2、前綴索引和索引選擇性

有時候需要索引很長的字符列,這會讓索引變得很大且很慢。此時可以有兩個策略,一個是自定義哈希索引,另一個就是前綴索引。

  • 前綴索引能大大節約索引空間,從而提高索引效率,但這樣也會降低索引的選擇性(索引選擇性——不重復的索引值和數據表記錄總數的比值);
  • 索引前綴長度的選擇——計算法。例如:LELECT COUNT(DISTINCT city)/COUNT() AS sel1, COUNT(DISTINCT LEFT(city, 3))/COUNT() AS sel2, …; 如果前綴的選擇性接近sel1就可以使用了。有時候只看平均選擇型也不靠譜,還需要做進一步判斷。
  • 缺點:MySQL無法使用前綴索引做ORDER BY和GROUP BY,也無法使用前綴索引做覆蓋掃描;
  • 有時候也可以使用前綴索引——可將對應列的字符串反序存儲,并創建前綴索引。

3.3、多列索引

為多列創建合適的索引

  • 多列索引。例如:key(col1, col2, col3);
  • MySQL5.0之后的版本引入了“索引合并”的策略,一定程度上可以使用表上的多個單列索引來定位表中的行;
  • 索引合并策略有時候是一種優化后的結果,但實際上更說明表上的索引建得很糟糕。
    • 當出現服務器對多個索引做相交操作時(多個AND),通常意味著需要一個包含相關列的多列索引,而不是多個獨立的單列索引;
    • 當服務器需要對多個索引做聯合操作時(多個OR),通常需要耗費大量的CPU和內存在算法的緩存、排序和合并上。

3.4、選擇合適的索引順序

  • 正確的索引順序依賴于使用該索引的查詢,并且同時需要考慮如何更好的滿足排序和分組的需要;
  • 索引可以按照升序或者降序進行掃描,以滿足精確符合列順序的ORDER BY 、GROUP BY和DISTINCT等子句的查詢需求;
  • 索引列順序的選擇——在不考慮分組和排序的情況下,將選擇性最高的列放到索引最前面(經驗法則);
  • 避免隨機I/O和排序;
  • 對于某些特殊用戶和分組,避免其使用普通的索引查詢。

3.5、聚簇索引

聚簇索引就是按照每張表的主鍵構造一顆B+樹,同時葉子節點中存放的就是整張表的行記錄數據,也將聚集索引的葉子節點稱為數據頁。這個特性決定了索引組織表中數據也是索引的一部分,每張表只能擁有一個聚簇索引。

Innodb通過主鍵聚集數據,如果沒有定義主鍵,innodb會選擇非空的唯一索引代替。如果沒有這樣的索引,innodb會隱式的定義一個主鍵來作為聚簇索引。

聚簇索引的優點:

  • 數據訪問更快,因為聚簇索引將索引和數據保存在同一個B+樹中,因此從聚簇索引中獲取數據比非聚簇索引更快
  • 聚簇索引對于主鍵的排序查找和范圍查找速度非常快

聚簇索引的缺點:

  • 插入速度嚴重依賴于插入順序,按照主鍵的順序插入是最快的方式,否則將會出現頁分裂,嚴重影響性能。因此,對于InnoDB表,我們一般都會定義一個自增的ID列為主鍵
  • 更新主鍵的代價很高,因為將會導致被更新的行移動。因此,對于InnoDB表,我們一般定義主鍵為不可更新。
  • 二級索引訪問需要兩次索引查找,第一次找到主鍵值,第二次根據主鍵值找到行數據。

3.6、覆蓋索引

通常開發人員會根據查詢的where條件來創建合適的索引,但是優秀的索引設計應該考慮到整個查詢。其實mysql可以使用索引來直接獲取列的數據。如果索引的葉子節點包含了要查詢的數據,那么就不用回表查詢了,也就是說這種索引包含(亦稱覆蓋)所有需要查詢的字段的值,我們稱這種索引為覆蓋索引

3.7、使用索引掃描排序

MySQL有兩種方式可以生成有序結果:通過排序操作;按照索引順序掃描。

  • 只有當索引的列順序和ORDER BY子句的順序完全一致,并且所有列的排序方向(升序/降序)都一樣時,MySQL才能使用索引來對結果做排序;
  • 當查詢需要關聯多張表時,只有當ORDER BY子句引用的字段全部來自第一張表時,才能使用索引排序;
  • ORDER BY子句中的字段需要滿足索引的最左前綴的要求,才能使用索引排序;
  • 當索引的前導列為常量時,ORDER BY子句可以不滿足索引的最左前綴要求也能使用索引排序。例如:key(rental_date, inventory_id, customer_id);… where rental_data=‘2018-01-08’ ORDER BY inventory_id DESC;

四、維護索引和表

維護表有三個目的:找到并修復損壞的表;維護準確的索引統計信息;減少碎片

4.1、更新索引統計信息

MySQL的查詢優化器會通過兩個API來了解存儲引擎的索引值的分布信息,已決定如何使用索引信息。

  • records_in_range();
  • info()。如果存儲引擎向優化器提供的索引統計信息不準確,就會導致優化器做出錯誤的優化決定,這會嚴重影響查詢性能。可通過執行ANALYZE TABLE 來重新生成統計信息以解決這個問題。

4.2、減少索引和數據的碎片

  • B-Tree索引可能會碎片化,碎片化的索引可能會以很差或無序的方式存儲在磁盤上,這會降低查詢效率;
  • 表數據存儲也可能碎片化。主要有行碎片行間碎片剩余空間碎片三種。對于MyISAM表,這三類碎片都可能發生,但InnoDB不會出現短小的行碎片,InnoDB會移動短小的行,并重寫到一個片段中。
  • 【維護方法】可通過執行POTIMIZE TABLE或者導出再導入來重新整理數據;對于那些不支持POTIMIZE TABLE命令的引擎,可以執行ALTER TABLE操作來重建表。只需要將表的存儲引擎改為當前的引擎即可。例如:ALTER TABLE <table> ENGINE=<engine>;

五、總結

索引是一個非常復雜的話題! MySQL和存儲引擎訪問數據的方式, 加上索引的特性,使得索引成為一個影響數據訪問的有力而靈活的工作(無論數據是在 磁盤中還是在內存中)。

在MySQL中,大多數情況下都會使用B-Tree索引。其他類型的索引大多只適用于特殊 的目的。如果在合適的場景中使用索引,將大大提高査詢的響應時間。

如果一個査詢無法從所有可能的索引中獲益,則應該看看是否可以創建一個更合適的索 引來提升性能。如果不行,也可以看看是否可以重寫該査詢,將其轉化成一個能夠高效 利用現有索引或者新創建索引的査詢。這也是下一章要介紹的內容。

參考:

《高性能 MySQL 第三版》

聚簇索引和非聚簇索引

mysql-覆蓋索引

創建高性能的索引

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

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

相關文章

linux 調優系列

Linux系統內核:修改TCP/IP調優參數 所有的TCP/IP調優參數都位于/proc/sys/net/目錄。例如, 下面是最重要的一些調優參數, 后面是它們的含義: 1. /proc/sys/net/core/rmem_max — 最大的TCP數據接收緩沖。 2. /proc/sys/net/core/wmem_max — 最大的TCP數據發送緩沖。 3.…

java中的構造方法與代碼塊

一、構造方法 1.1、java中的構造方法跟普通方法有很大的區別&#xff1a; 構造方法的方法名跟類名相同構造方法沒有返回值類型,連void也沒有,也不能用return返回值每次創建一個對象,都會調用構造方法,如果沒有寫構造方法,系統會默認加上一個空參的構造,如果已經寫了構造方法,…

bash shell是如何識別特殊符號的

一 、 shell命令解析以及識別通配符 Shell是系統的用戶界面,提供了用戶與內核進行交互操作的一種接口。它接收用戶輸入的命令并把它送入內核去執行 。 實際上Shell是一個命令解釋器,它解釋由用戶輸入的命令并且把它們送到內核。不僅如此,Shell有自己的編程語言用于對命令的編…

linux 調優系列(續)

linux 的各大發行版&#xff0c;都有些不必要的服務被默認開啟了&#xff0c;針對ubuntu&#xff0c;我們 可以采用選擇性關閉的方法加速起動&#xff0c;提高系統性能。 這里我們安裝一個軟件&#xff1a; sudo apt-get install sysv-rc-conf 然后這樣起動&#xff1a; 在這個…

配置文件bashrc與profile的區別

1、當登入系統時候獲得-個shell進程時&#xff0c;其讀取環境設定檔有三步 首先讀入的是全局環境變量設定檔/ete/profile,然后根據其內容讀取額外的設定的文檔&#xff0c;如/etc/profile. d和/ etc/ inputre 然后根據不同使用者帳號&#xff0c;去其家目錄讀取, bash, pr…

高性能MySQL(4)——查詢性能優化

査詢優化、索引優化、庫表結構優化需要齊頭并進&#xff0c;一個不落。 一、為什么查詢速度為變慢 在嘗試編寫快速的查詢之前,需要清楚一點,真正重要是響應時間。如果把查詢看作是一個任務&#xff0c;那么他由一系列子任務組成&#xff0c;每個子任務都會消耗一定的時間。如果…

GooglePerformanceTools--tcmalloc

TCmalloc全稱是Thread-Caching malloc&#xff0c;作者宣稱tcmalloc相對于glibc2.3 malloc(aka ptmalloc2)有6倍的性能提高&#xff0c;tcmalloc的常用場景是用于加速MySQL&#xff0c;不過據Wikipedia的hacker Domas Mituzas說&#xff0c;tcmalloc不僅僅對MySQL起作用&#x…

linux基本命令以及命令常用選項

linux基本命令以及命令常用選項touch 創建文件&#xff0c;改變恩建時間戳&#xff0c;如果直接跟上一個文件&#xff0c;該文件不存在則創建文件-c文件不存在不創建文件&#xff0c;存在則改變文件的時間戳-a只改變文件的訪問時間-m改變文件的修改時間-t時間格式CCYYMMDDhhmm…

Java獲取上一周、上一個月、上一年的時間

SimpleDateFormat format new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”); Calendar c Calendar.getInstance(); 1.過去七天 c.setTime(new Date()); c.add(Calendar.DATE, - 7); Date d c.getTime(); String day format.format(d); System.out.println(“過去七天&#…

遠程網絡安裝RHEL5

一&#xff1a;Linux安裝工作原理 眾所周知&#xff0c;在安裝過程中Linux首先需要一個引導程序來讓安裝光盤啟動&#xff0c;再實行配置與安裝。但目前轉化為遠程網絡安裝那么就需要我們的安裝程序能夠遠程地通過網絡傳送給客戶端。因此在搭建遠程Linux安裝服務器時候首先要值…

sed命令操作

sed 是一種數據流編輯器,它一次處理一行內容,處理時,把當前處理的行存儲在臨時緩沖區(pattern space稱為“模式空間”)中,在內存中處理,完成后把該行發送到屏幕上,清理pattern space中的內容,接著重復剛才的動作,讀入下一行,直到文件處理結束。文件內容并沒有 改變,…

Portainer簡介及部署

一、介紹 Portainer是Docker的圖形化管理工具&#xff0c;提供狀態顯示面板、應用模板快速部署、容器鏡像網絡數據卷的基本操作&#xff08;包括上傳下載鏡像&#xff0c;創建容器等操作&#xff09;、事件日志顯示、容器控制臺操作、Swarm集群和服務等集中管理和操作、登錄用…

Nexus搭建Maven私有倉庫

一、使用Docker安裝Nexus 1、查詢當前有哪些Nexus鏡像 docker search nexus2、下載sonatype/nexus3 docker pull docker.io/sonatype/nexus33、運行nexus容器 mkdir -p /usr/local/nexus3/nexus-data #新建掛載目錄 chown -R 200 /usr/local/nexus3/nexus-datadocker run -…

VI資料收集

1.6.1 vi 的工作模式Vi 在初始啟動后首先進入編輯模式&#xff0c;這時用戶可以利用一些預先定義的按鍵來移動光標、刪除文字、復制或粘貼文字等。這些按鍵均是普通的字符&#xff0c;例如 l 是向右移動光標&#xff0c;相當于向右箭頭鍵&#xff0c;k 是向下移動光標&#xff…

linux終端

終端就是處理計算機主機輸入輸出的一套設備&#xff0c;它用來顯示主機運算的輸出&#xff0c;并且接受主機要求的輸入&#xff0c;典型的終端包括顯示器鍵盤套件&#xff0c;打印機打字機套件等 linux終端類型終端名稱標識含義串行端口終端Serial Port Terminal/dev/ttySx 串行…

日常問題——VMware下的CentOS7 Ping不通百度

問題描述&#xff1a; 在VMware下新創建的CentOS ping 不通百度 解決方案&#xff1a; 1、點擊VMware的編輯按鈕下的虛擬網絡編輯器 2、更改設置后&#xff0c;選擇NAT類型&#xff0c;點擊NAT設置 3、記錄下&#xff0c;子網ip&#xff0c;掩碼&#xff0c;網管IP信息 4、…

linux查找文件find

查找命令文件whatis 從path還從man中查找which 從path環境變量中查找文件查找locate /var/lib/mlocate/mlocate.db 通過update更新數據庫 find 默認動作是 -print -ls -delete -ok -exec 命令 {} \; -name根據文件名查找-iname忽略大小寫-size根據文件及目錄大小查找…

linux下用ntp對時

更新系統時間的命令用&#xff1a;ntpdate <時間服務器>教育網下常用的時間服務器有s1a.time.edu.cn&#xff0c;或者210.72.145.44ntpdate 210.72.145.44更多教育下的時間服務器可在這里找到&#xff1a; http://www.time.edu.cn/mem.htm。如果想讓系統退出時的把時間寫…

CentOS7.6下安裝Ambari

一、準備工作 1.1、準備三臺CentOS 1.2、配置靜態IP、DNS vi /etc/sysconfig/network-scripts/ficfg-ens33IPADDR為 配置的ip NETMASK 子網掩碼 GATEWAY 網關 配置保存后重啟虛擬網絡 service network restart1.3、配置Hostname vi /etc/hostname#將第一行替換成新名字 m…

多主機推送公鑰、修改配置、修改密碼腳本

推送公鑰&#xff1a; !#/bin/bash if [! -f ~/.ssh/id_rsa ] ;thenssh-keygen -P "" -f ~/.ssh/id_rsa fifor i in seq 100 do {ip192.168.1.$iping -c1 $ip &>/dev/nullif [ $? -eq 0];thenecho $ip |tee addreee/usr/bin/expect<<-EOFset time 10…