主頁 > 資料庫 > 2022 老生常談 深入理解用好MySQL索引

2022 老生常談 深入理解用好MySQL索引

2022-04-29 08:30:41 資料庫

尊重原創著作權: https://www.gewuweb.com/hot/11908.html

圖解|用好MySQL索引,你需要知道的一些事情

尊重原創著作權: https://www.gewuweb.com/sitemap.html

一篇文章來聊一聊如何用好MySQL索引,

圖解|用好MySQL索引,你需要知道的一些事情

為了更好地進行解釋,我創建了一個存盤引擎為InnoDB的表user_innodb,并批量初始化了500W+條資料,包含主鍵id、姓名欄位(name)、性別欄位(gender,用0,1表示不同性別)、手機號欄位(phone),并為name和phone欄位創建了聯合索引,

CREATE TABLE user_innodb ( id int NOT NULL AUTO_INCREMENT, name
varchar(255) DEFAULT NULL, gender tinyint(1) DEFAULT NULL, phone
varchar(11) DEFAULT NULL, PRIMARY KEY (id), INDEX IDX_NAME_PHONE (name,
phone)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

1. 索引的代價

索引可以非常有效地提升查詢效率,既然這么好,我給每個欄位都創建一個索引行不行?我勸你不要沖動,

圖解|用好MySQL索引,你需要知道的一些事情

任何事情都有兩面,索引也不例外,過度使用索引,我們在空間和時間上都會付出相應的代價,

1.1 空間上的代價

索引就是一棵B+數,每創建一個索引都需要創建一棵B+樹,每一棵B+樹的節點都是一個資料頁,每一個資料頁默認會占用16KB的磁盤空間,每一棵B+樹又會包含許許多多的資料頁,所以,大量創建索引,你的磁盤空間會被迅速消耗,

1.2 時間上的代價

空間上的代價你可以使用“鈔能力”來解決,但時間上的代價我們可能就束手無策了,

鏈表的維護

我以主鍵索引為例舉個例子,主鍵索引的B+樹的每一個節點內的記錄都是按照主鍵值由小到大的順序,采用單向鏈表的方式進行連接的,如下圖所示:

圖解|用好MySQL索引,你需要知道的一些事情

如果我現在要洗掉主鍵id為1的記錄,會破壞3個資料頁內的記錄排序,需要對這3個資料頁內的記錄進行重排列,插入和修改操作也是同理,

注:這里給大家提一嘴,其實洗掉操作并不會立即進行資料頁內記錄的重排列,而是會給被洗掉的記錄打上一個洗掉的標識,等到合適的時候,再把記錄從鏈表中移除,但是總歸需要涉及到排序的維護,勢必要消耗性能,

假如這張表有12個欄位,我們為這張表的12個欄位都設定了索引,我們洗掉1條記錄,需要涉及到12棵B+樹的N個資料頁內記錄的排序維護,

更糟糕的是,你增刪改記錄的時候,還可能會觸發資料頁的回收和分裂,還是以上圖為例,假如我洗掉了id為13的記錄,那么資料頁124就沒有存在的必要了,會被InnoDB存盤引擎回收;我插入一條id為12的記錄,如果資料頁32的空間不足以存盤該記錄,InnoDB又需要進行頁面分裂,我們不需要知道頁面回收和頁面分裂的細節,但是能夠想象到這個操作會有多復雜,

如果每個欄位都創建索引,所有這些索引的維護操作帶來的性能損耗,你能想象了吧,

查詢計劃

執行查詢陳述句之前,MySQL查詢優化器會基于cost成本對一條查詢陳述句進行優化,并生成一個執行計劃,如果創建的索引太多,優化器會計算每個索引的搜索成本,導致在分析程序中耗時太多,最終影響查詢陳述句的執行效率,

2. 回表的代價

2.1 什么是回表

我再啰嗦一遍什么是回表,我們可以通過二級索引找到B+樹中的葉子結點,但是二級索引的葉子節點的內容并不全,只有索引列的值和主鍵值,我們需要拿著主鍵值再去聚簇索引(主鍵索引)的葉子節點中去拿到完整的用戶記錄,這個程序叫做回表,

圖解|用好MySQL索引,你需要知道的一些事情

上圖中我以name二級索引為例,并且只畫出了二級索引的葉子節點和聚簇索引的葉子節點,省略了兩棵B+樹的非葉子節點,

從二級索引的葉子節點延伸出的3條線表示的就是回表操作,

2.2 回表的代價

我們根據name欄位查找二級索引的葉子節點的代價還是比較小的,原因有二:

  1. 葉子節點所在的頁通過雙向鏈表進行關聯,遍歷的速度比較快;
  2. MySQL會盡量讓同一個索引的葉子節點的資料頁在磁盤空間中相鄰,盡力避免隨機IO,

但是二級索引葉子節點中的主鍵id的排布就沒有任何規律了,畢竟name索引是對name欄位進行排序的,進行回表的時候,極有可能出現主鍵id所在的記錄在聚簇索引葉子節點中反復橫跳的情況(正如上圖中回表的3條線表示的那樣),也就是隨機IO,如果目標資料頁恰好在記憶體中的話效果倒也不會太差,但如果不在記憶體中,還要從磁盤中加載一個資料頁的內容(16KB)到記憶體中,這個速度可就太慢了,

是不是說完了回表的代價之后,我會給出一種更高效的搜索方式?不是,回表已經是一種比較高效的搜索方式了,我們需要做的就是盡量地減少回表操作帶來的損耗,總結起來就是兩點:

  1. 能不回表就不回;
  2. 必須回表就減少回表的次數,

接下來先給大家介紹兩個與回表相關的重要概念,這兩個概念涉及到的方法也是索引使用原則的一部分,因為比較重要,在這里我把這兩個概念先解釋給大家聽,

3. 索引覆寫、索引下推

3.1 索引覆寫

想一下,如果非聚簇索引的葉子節點上有你想要的所有資料,是不是就不需要回表了呢?比如我為name和phone欄位創建了一個聯合索引,如下圖:

圖解|用好MySQL索引,你需要知道的一些事情

如果我們恰好只想搜索name、phone以及主鍵欄位,

SELECT id, name, phone FROM user_innodb WHERE name = "蟬沐風";

可以直接從葉子節點獲取所有資料,根本不需要回表操作,

我們把索引中已經包含了所有需要讀取的列資料的查詢方式稱為 覆寫索引 (或 索引覆寫 ),

3.2 索引下推

3.2.1 概念

還是拿name和phone的聯合索引為例,我們要查詢所有name為「蟬沐風」,并且手機尾號為6606的記錄,查詢SQL如下:

SELECT * FROM user_innodb WHERE name = "蟬沐風" AND phone LIKE "%6606";

由于聯合索引的葉子節點的記錄是先按照name欄位排序,name欄位相同的情況下再按照phone欄位排序,因此把%加在phone欄位前面的時候,是無法利用索引的順序性來進行快速比較的,也就是說這條查詢陳述句中只有name欄位可以使用索引進行快速比較和過濾,正常情況下查詢程序是這個樣子的:

  1. InnoDB使用聯合索引查出所有name為蟬沐風的二級索引資料,得到3個主鍵值:3485,78921,423476;

  2. 拿到主鍵索引進行回表,到聚簇索引中拿到這三條完整的用戶記錄;

  3. InnoDB把這3條完整的用戶記錄回傳給MySQL的Server層,在Server層過濾出尾號為6606的用戶,

如下面兩幅圖所示,第一幅圖表示InnoDB通過3次回表拿到3條完整的用戶記錄,交給Server層;第二幅圖表示Server層經過phone LIKE
"%6606"條件的過濾之后找到符合搜索條件的記錄,返給客戶端,

圖解|用好MySQL索引,你需要知道的一些事情

圖解|用好MySQL索引,你需要知道的一些事情

值得我們關注的是,索引的使用是在存盤引擎中進行的,而資料記錄的比較是在Server層中進行的,現在我們把上述搜索考慮地極端一點,假如資料表中10萬條記錄都符合name='蟬沐風'的條件,而只有1條符合phone
LIKE
"%6606"條件,這就意味著,InnoDB需要將99999條無效的記錄傳輸給Server層讓其自己篩選,更嚴重的是,這99999條資料都是通過回表搜索出來的啊!關于回表的代價你已經知道了,

現在引入 索引下推 ,準確來說,應該叫做 索引條件下推 (Index Condition Pushdown, ICP
),就是過濾的動作由下層的存盤引擎層通過使用索引來完成,而不需要上推到Server層進行處理,ICP是在MySQL5.6之后完善的功能,

再回顧一下,我們第一步已經通過name =
"蟬沐風"在聯合索引的葉子節點中找到了符合條件的3條記錄,而且phone欄位也恰好在聯合索引的葉子節點的記錄中,這個時候可以直接在聯合索引的葉子節點中進行遍歷,篩選出尾號為6606的記錄,找到主鍵值為78921的記錄,最后只需要進行1次回表操作即可找到符合全部條件的1條記錄,回傳給Server層,

很明顯,使用ICP的方式能有效減少回表的次數,

另外,ICP是默認開啟的,對于二級索引,只要能把條件甩給下面的存盤引擎,存盤引擎就會進行過濾,不需要我們干預,

3.2.2 演示

查看一下當前ICP的狀態:

SHOW VARIABLES LIKE 'optimizer_switch';

圖解|用好MySQL索引,你需要知道的一些事情

執行以下SQL陳述句,并用EXPLAIN查看一下執行計劃,此時的執行計劃是Using index condition

EXPLAIN SELECT * FROM user_innodb WHERE name = "蟬沐風" AND phone LIKE "%6606";

圖解|用好MySQL索引,你需要知道的一些事情

然后關閉ICP

SET optimizer_switch="index_condition_pushdown=off";

再查看一下ICP的狀態

圖解|用好MySQL索引,你需要知道的一些事情

再次執行查詢陳述句,并用EXPLAIN查看一下執行計劃,此時的執行計劃是Using where

EXPLAIN SELECT * FROM user_innodb WHERE name = "蟬沐風" AND phone LIKE "%6606";

圖解|用好MySQL索引,你需要知道的一些事情

注:即使滿足索引下推的使用條件,查詢優化器也未必會使用索引下推,因為可能存在更高效的方式,

由于之前我給name欄位創建了索引,導致一直沒有使用索引下推,EXPLAIN陳述句顯示使用了name索引,而不是name和phone的聯合索引;洗掉name索引之后,才獲得上述截圖的效果,大家做實驗的時候需要注意,

到目前為止大家應該清楚了索引和回表帶來的性能問題,講這些自然不是為了恐嚇大家讓大家遠離索引,相反,我們要以正確的方式積極擁抱索引,最大限度降低其帶來的負面影響,放大其優勢,如何用好索引,從兩個方面考慮:

  1. 高效發揮已經創建的索引的作用(避免索引失效)
  2. 為合適的列創建合適的索引(索引創建原則)

4. 什么時候索引會失效?

4.1 違反最左前綴原則

拿我們文章開始創建的聯合索引為例,該聯合索引的B+樹資料頁內的記錄首先按照name欄位進行排序,name欄位相同的情況下,再按照phone欄位進行排序,

所以,如果我們直接使用phone欄位進行搜索,無法利用索引的順序性,

EXPLAIN SELECT * FROM user_innodb WHERE phone = "13203398311";

圖解|用好MySQL索引,你需要知道的一些事情

EXPLAIN可以查看搜索陳述句的執行計劃,其中,possible_keys串列示在當前查詢中,可能用到的索引有哪一些;key串列示實際用到的索引有哪一些,

但是一旦加上name的搜索條件,就會使用到聯合索引,而且不需要在意name在WHERE子句中的位置,因為查詢優化器會幫我們優化,

EXPLAIN SELECT * FROM user_innodb WHERE phone = "13203398311" AND name =
'蟬沐風';

圖解|用好MySQL索引,你需要知道的一些事情

4.2 使用反向查詢(!=, <>,NOT LIKE)

MySQL在使用反向查詢(!=, <>, NOT LIKE)的時候無法使用索引,會導致全表掃描,覆寫索引除外,

EXPLAIN SELECT * FROM user_innodb WHERE name != '蟬沐風';

圖解|用好MySQL索引,你需要知道的一些事情

4.3 LIKE以通配符開頭

當使用name LIKE '%沐風'或者name LIKE
'%沐%'這兩種方式都會使索引失效,因為聯合索引的B+樹資料頁內的記錄首先按照name欄位進行排序,這兩種搜索方式不在意name欄位的開頭是什么,自然就無法使用索引,只能通過全表掃描的方式進行查詢,

EXPLAIN SELECT * FROM user_innodb WHERE name LIKE '%沐風';

圖解|用好MySQL索引,你需要知道的一些事情

但是使用通配符結尾就沒有問題

EXPLAIN SELECT * FROM user_innodb WHERE name LIKE '蟬沐%';

圖解|用好MySQL索引,你需要知道的一些事情

4.4 對索引列做任何操作

如果不是單純使用索引列,而是對索引列做了其他操作,例如數值計算、使用函式、(手動或自動)型別轉換等操作,會導致索引失效,

4.4.1 使用函式

EXPLAIN SELECT * FROM user_innodb WHERE LEFT(name,3) = '蟬沐風';

圖解|用好MySQL索引,你需要知道的一些事情

MySQL8.0新增了函式索引的功能,我們可以給函式作用之后的結果創建索引,使用以下陳述句

ALTER TABLE user_innodb ADD KEY IDX_NAME_LEFT ((left(name,3)));

再次執行EXPLAIN陳述句,此時索引生效

圖解|用好MySQL索引,你需要知道的一些事情

4.4.2 使用運算式

EXPLAIN SELECT * FROM user_innodb WHERE id + 1 = 1100000;

圖解|用好MySQL索引,你需要知道的一些事情

換一種方式,單獨使用id,就能高效使用索引:

EXPLAIN SELECT * FROM user_innodb WHERE id = 1100000 - 1;

圖解|用好MySQL索引,你需要知道的一些事情

4.4.3 使用型別轉換

例1

user_innodb中的phone欄位為varchar型別,實驗之前我們先給phone欄位創建個索引

ALTER TABLE user_innodb ADD INDEX IDX_PHONE (phone);

隨便搜索一個存在的手機號,看一下索引是否成功

EXPLAIN SELECT * FROM user_innodb WHERE phone = '13203398311';

圖解|用好MySQL索引,你需要知道的一些事情

可以看到能使用到索引,現在我們稍微修改一下,把phone = '13203398311'修改為phone =
13203398311,這意味著我們將字串的搜索條件改成了整形的搜索條件,再看一下還會不會使用到索引:

EXPLAIN SELECT * FROM user_innodb WHERE phone = 13203398311;

圖解|用好MySQL索引,你需要知道的一些事情

顯示索引失效,

例2

我們再看一個例子,主鍵id型別是bigint,但是在搜索條件中我估計使用字串型別:

EXPLAIN SELECT * FROM user_innodb WHERE id = '1099999';

圖解|用好MySQL索引,你需要知道的一些事情

總結

稍微總結一下這個問題,當索引欄位型別為字串時,使用數字型別進行搜索不會用到索引;而索引欄位型別為數字型別時,使用字串型別進行搜索會使用到索引,

要搞明白這個問題,我們需要知道MySQL的資料型別轉換規則是什么,簡單地說就是MySQL會自動將數字轉化為字串,還是將字串轉化為數字,

一個簡單的方法是,通過SELECT '10' > 9的結果來確定MySQL的型別轉換規則:

  • 結果為1,說明MySQL會自動將字串型別轉化為數字,相當于執行了SELECT 10 > 9;
  • 結果為0,說明MySQL會自動將數字轉化為字串,相當于執行了SELECT '10' > '9',

mysql> SELECT '10' > 9;+----------+| '10' > 9 |+----------+| 1 |+----------+1
row in set (0.00 sec)

上面的執行結果為1,說明MySQL遇到型別轉換時,會自動將字串轉換為數字型別,因此對于例1:

EXPLAIN SELECT * FROM user_innodb WHERE phone = 13203398311;

就相當于

EXPLAIN SELECT * FROM user_innodb WHERE CAST(phone AS signed int) =
13203398311;

也就是對索引欄位使用了函式,按照前文的介紹,對索引使用函式是不會使用到索引的,

對于例2:

EXPLAIN SELECT * FROM user_innodb WHERE id = '1099999';

就相當于

EXPLAIN SELECT * FROM user_innodb WHERE id = CAST('1099999' AS unsigned int);

沒有在索引欄位添加任何操作,因此能夠使用到索引,

4.5 OR連接

使用OR連接的查詢陳述句,如果OR之前的條件列是索引列,但是OR之后的條件列不是索引列,則不會使用索引,舉例:

EXPLAIN SELECT * FROM user_innodb WHERE id = 1099999 OR gender = 0;

圖解|用好MySQL索引,你需要知道的一些事情

上面總結了一些索引失效的場景,這些經驗的總結往往對SQL的優化很有益處,但同時需要注意的是這些經驗并非金科玉律,

比如使用<>查詢時,在某些時候是可以用到索引的:

EXPLAIN SELECT * FROM user_innodb WHERE id <> 1099999;

圖解|用好MySQL索引,你需要知道的一些事情

最終是否使用索引,完全取決于MySQL的優化器,而優化器的判定依據就是cost開銷(Cost Base
Optimizer),優化器并非基于具體的規則,也不是基于語意,就是單純地執行開銷小的方案罷了,所以在·EXPLAIN·的結果中你會看到possible_keys一列,優化器會把這里邊的索引都試一遍(是不是又加深了對不能隨便創建索引的認識呢?),然后選一個開銷最小的,如果都不太行,那就直接全表掃描好了,

而cost開銷,和資料庫版本、資料量等都有關系,因此如果想更精準地提升索引功能性,擁抱EXPLAIN吧!

5. 索引創建(使用)原則

之前講過的 索引覆寫索引下推 都可以作為索引創建的原則,就是在創建索引的時候,盡量發揮 索引覆寫索引下推
的優勢,

盡量避免上述提及到的索引可能失效的情況的出現,同樣是索引的使用原則,

除此之外,再給大家介紹一些,

5.1 不為離散度高的列創建索引

先來看一下列的離散度公式:COUNT(DISTINCT(column_name)) /
COUNT(*),列的不重復值的個數與所有資料行的比例,簡而言之,如果列的重復值越多,列的離散度越低,重復值越少,離散度就越高,

舉個例子,gender(性別)列只有0、1兩個值,列的離散度非常低,假如我們為該列創建索引,我們會在二級索引中搜索到大量的重復資料,然后進行大量回表操作,大量回表哈?你懂了吧,

不要為重復值多的列創建索引

5.2 只為用于搜索、排序或分組的列創建索引

我們只為出現在WHERE子句中的列或者出現在ORDER BY和GROUP BY子句中的列創建索引即可,僅出現在查詢串列中的列不需要創建索引,

5.3 用好聯合索引

用2條SQL陳述句來說明這個問題:

1. SELECT * FROM user_innodb WHERE name = '蟬沐風' AND phone = '13203398311';2.
SELECT * FROM user_innodb WHERE name = '蟬沐風';

陳述句1和陳述句2都能夠使用索引,這帶給我們的一個索引設計原則就是:

不要為聯合索引的第一個索引列單獨創建索引

因為聯合索引本身就是先按照name列進行排序,因此聯合索引對name的搜索是有效的,不需要單獨為name再創建索引了,也正因為此

建立聯合索引的時候,一定要把最常用的列放在最左邊

5.4 對過長的欄位,建立前綴索引

如果一個字串格式的列占用的空間比較大(就是說允許存盤比較長的字串資料),為該列創建索引,就意味著該列的資料會被完整地記錄在每個資料頁的每條記錄中,會占用相當大的存盤空間,

對此,我們可以為該列的前幾個字符創建索引,也就是在二級索引的記錄中只會保留字串的前幾個字符,比如我們可以為phone列創建索引,索引只保留手機號的前3位:

ALTER TABLE user_innodb ADD INDEX IDX_PHONE_3 (phone(3));

然后執行下面的SQL陳述句:

EXPLAIN SELECT * FROM user_innodb WHERE phone = '1320';

圖解|用好MySQL索引,你需要知道的一些事情

由于在IDX_PHONE_3索引中只保留了手機號的前3位數字,所以我們只能定位到以132開頭的二級索引記錄,然后在遍歷所有的這些二級索引記錄時再判斷它們是否滿足第4位數為0的條件,

當列中存盤的字串包含的字符較多時,為該欄位建立前綴索引可以有效節省磁盤空間

5.5 頻繁更新的值,不要作為主鍵或索引

因為可能涉及到資料頁分裂的情況,會影響性能,

5.6 隨機無序的值,不建議作為索引,例如身份證、UUID

不建議作為索引,例如身份證、UUID

尊重原創著作權: https://www.gewuweb.com/sitemap.html

尊重原創著作權: https://www.gewuweb.com/hot/13713.html

圖解|用好MySQL索引,你需要知道的一些事情

一篇文章來聊一聊如何用好MySQL索引,

圖解|用好MySQL索引,你需要知道的一些事情

為了更好地進行解釋,我創建了一個存盤引擎為InnoDB的表user_innodb,并批量初始化了500W+條資料,包含主鍵id、姓名欄位(name)、性別欄位(gender,用0,1表示不同性別)、手機號欄位(phone),并為name和phone欄位創建了聯合索引,

CREATE TABLE user_innodb ( id int NOT NULL AUTO_INCREMENT, name
varchar(255) DEFAULT NULL, gender tinyint(1) DEFAULT NULL, phone
varchar(11) DEFAULT NULL, PRIMARY KEY (id), INDEX IDX_NAME_PHONE (name,
phone)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

1. 索引的代價

索引可以非常有效地提升查詢效率,既然這么好,我給每個欄位都創建一個索引行不行?我勸你不要沖動,

圖解|用好MySQL索引,你需要知道的一些事情

任何事情都有兩面,索引也不例外,過度使用索引,我們在空間和時間上都會付出相應的代價,

1.1 空間上的代價

索引就是一棵B+數,每創建一個索引都需要創建一棵B+樹,每一棵B+樹的節點都是一個資料頁,每一個資料頁默認會占用16KB的磁盤空間,每一棵B+樹又會包含許許多多的資料頁,所以,大量創建索引,你的磁盤空間會被迅速消耗,

1.2 時間上的代價

空間上的代價你可以使用“鈔能力”來解決,但時間上的代價我們可能就束手無策了,

鏈表的維護

我以主鍵索引為例舉個例子,主鍵索引的B+樹的每一個節點內的記錄都是按照主鍵值由小到大的順序,采用單向鏈表的方式進行連接的,如下圖所示:

圖解|用好MySQL索引,你需要知道的一些事情

如果我現在要洗掉主鍵id為1的記錄,會破壞3個資料頁內的記錄排序,需要對這3個資料頁內的記錄進行重排列,插入和修改操作也是同理,

注:這里給大家提一嘴,其實洗掉操作并不會立即進行資料頁內記錄的重排列,而是會給被洗掉的記錄打上一個洗掉的標識,等到合適的時候,再把記錄從鏈表中移除,但是總歸需要涉及到排序的維護,勢必要消耗性能,

假如這張表有12個欄位,我們為這張表的12個欄位都設定了索引,我們洗掉1條記錄,需要涉及到12棵B+樹的N個資料頁內記錄的排序維護,

更糟糕的是,你增刪改記錄的時候,還可能會觸發資料頁的回收和分裂,還是以上圖為例,假如我洗掉了id為13的記錄,那么資料頁124就沒有存在的必要了,會被InnoDB存盤引擎回收;我插入一條id為12的記錄,如果資料頁32的空間不足以存盤該記錄,InnoDB又需要進行頁面分裂,我們不需要知道頁面回收和頁面分裂的細節,但是能夠想象到這個操作會有多復雜,

如果每個欄位都創建索引,所有這些索引的維護操作帶來的性能損耗,你能想象了吧,

查詢計劃

執行查詢陳述句之前,MySQL查詢優化器會基于cost成本對一條查詢陳述句進行優化,并生成一個執行計劃,如果創建的索引太多,優化器會計算每個索引的搜索成本,導致在分析程序中耗時太多,最終影響查詢陳述句的執行效率,

2. 回表的代價

2.1 什么是回表

我再啰嗦一遍什么是回表,我們可以通過二級索引找到B+樹中的葉子結點,但是二級索引的葉子節點的內容并不全,只有索引列的值和主鍵值,我們需要拿著主鍵值再去聚簇索引(主鍵索引)的葉子節點中去拿到完整的用戶記錄,這個程序叫做回表,

圖解|用好MySQL索引,你需要知道的一些事情

上圖中我以name二級索引為例,并且只畫出了二級索引的葉子節點和聚簇索引的葉子節點,省略了兩棵B+樹的非葉子節點,

從二級索引的葉子節點延伸出的3條線表示的就是回表操作,

2.2 回表的代價

我們根據name欄位查找二級索引的葉子節點的代價還是比較小的,原因有二:

  1. 葉子節點所在的頁通過雙向鏈表進行關聯,遍歷的速度比較快;
  2. MySQL會盡量讓同一個索引的葉子節點的資料頁在磁盤空間中相鄰,盡力避免隨機IO,

但是二級索引葉子節點中的主鍵id的排布就沒有任何規律了,畢竟name索引是對name欄位進行排序的,進行回表的時候,極有可能出現主鍵id所在的記錄在聚簇索引葉子節點中反復橫跳的情況(正如上圖中回表的3條線表示的那樣),也就是隨機IO,如果目標資料頁恰好在記憶體中的話效果倒也不會太差,但如果不在記憶體中,還要從磁盤中加載一個資料頁的內容(16KB)到記憶體中,這個速度可就太慢了,

是不是說完了回表的代價之后,我會給出一種更高效的搜索方式?不是,回表已經是一種比較高效的搜索方式了,我們需要做的就是盡量地減少回表操作帶來的損耗,總結起來就是兩點:

  1. 能不回表就不回;
  2. 必須回表就減少回表的次數,

接下來先給大家介紹兩個與回表相關的重要概念,這兩個概念涉及到的方法也是索引使用原則的一部分,因為比較重要,在這里我把這兩個概念先解釋給大家聽,

3. 索引覆寫、索引下推

3.1 索引覆寫

想一下,如果非聚簇索引的葉子節點上有你想要的所有資料,是不是就不需要回表了呢?比如我為name和phone欄位創建了一個聯合索引,如下圖:

圖解|用好MySQL索引,你需要知道的一些事情

如果我們恰好只想搜索name、phone以及主鍵欄位,

SELECT id, name, phone FROM user_innodb WHERE name = "蟬沐風";

可以直接從葉子節點獲取所有資料,根本不需要回表操作,

我們把索引中已經包含了所有需要讀取的列資料的查詢方式稱為 覆寫索引 (或 索引覆寫 ),

3.2 索引下推

3.2.1 概念

還是拿name和phone的聯合索引為例,我們要查詢所有name為「蟬沐風」,并且手機尾號為6606的記錄,查詢SQL如下:

SELECT * FROM user_innodb WHERE name = "蟬沐風" AND phone LIKE "%6606";

由于聯合索引的葉子節點的記錄是先按照name欄位排序,name欄位相同的情況下再按照phone欄位排序,因此把%加在phone欄位前面的時候,是無法利用索引的順序性來進行快速比較的,也就是說這條查詢陳述句中只有name欄位可以使用索引進行快速比較和過濾,正常情況下查詢程序是這個樣子的:

  1. InnoDB使用聯合索引查出所有name為蟬沐風的二級索引資料,得到3個主鍵值:3485,78921,423476;

  2. 拿到主鍵索引進行回表,到聚簇索引中拿到這三條完整的用戶記錄;

  3. InnoDB把這3條完整的用戶記錄回傳給MySQL的Server層,在Server層過濾出尾號為6606的用戶,

如下面兩幅圖所示,第一幅圖表示InnoDB通過3次回表拿到3條完整的用戶記錄,交給Server層;第二幅圖表示Server層經過phone LIKE
"%6606"條件的過濾之后找到符合搜索條件的記錄,返給客戶端,

圖解|用好MySQL索引,你需要知道的一些事情

圖解|用好MySQL索引,你需要知道的一些事情

值得我們關注的是,索引的使用是在存盤引擎中進行的,而資料記錄的比較是在Server層中進行的,現在我們把上述搜索考慮地極端一點,假如資料表中10萬條記錄都符合name='蟬沐風'的條件,而只有1條符合phone
LIKE
"%6606"條件,這就意味著,InnoDB需要將99999條無效的記錄傳輸給Server層讓其自己篩選,更嚴重的是,這99999條資料都是通過回表搜索出來的啊!關于回表的代價你已經知道了,

現在引入 索引下推 ,準確來說,應該叫做 索引條件下推 (Index Condition Pushdown, ICP
),就是過濾的動作由下層的存盤引擎層通過使用索引來完成,而不需要上推到Server層進行處理,ICP是在MySQL5.6之后完善的功能,

再回顧一下,我們第一步已經通過name =
"蟬沐風"在聯合索引的葉子節點中找到了符合條件的3條記錄,而且phone欄位也恰好在聯合索引的葉子節點的記錄中,這個時候可以直接在聯合索引的葉子節點中進行遍歷,篩選出尾號為6606的記錄,找到主鍵值為78921的記錄,最后只需要進行1次回表操作即可找到符合全部條件的1條記錄,回傳給Server層,

很明顯,使用ICP的方式能有效減少回表的次數,

另外,ICP是默認開啟的,對于二級索引,只要能把條件甩給下面的存盤引擎,存盤引擎就會進行過濾,不需要我們干預,

3.2.2 演示

查看一下當前ICP的狀態:

SHOW VARIABLES LIKE 'optimizer_switch';

圖解|用好MySQL索引,你需要知道的一些事情

執行以下SQL陳述句,并用EXPLAIN查看一下執行計劃,此時的執行計劃是Using index condition

EXPLAIN SELECT * FROM user_innodb WHERE name = "蟬沐風" AND phone LIKE "%6606";

圖解|用好MySQL索引,你需要知道的一些事情

然后關閉ICP

SET optimizer_switch="index_condition_pushdown=off";

再查看一下ICP的狀態

圖解|用好MySQL索引,你需要知道的一些事情

再次執行查詢陳述句,并用EXPLAIN查看一下執行計劃,此時的執行計劃是Using where

EXPLAIN SELECT * FROM user_innodb WHERE name = "蟬沐風" AND phone LIKE "%6606";

圖解|用好MySQL索引,你需要知道的一些事情

注:即使滿足索引下推的使用條件,查詢優化器也未必會使用索引下推,因為可能存在更高效的方式,

由于之前我給name欄位創建了索引,導致一直沒有使用索引下推,EXPLAIN陳述句顯示使用了name索引,而不是name和phone的聯合索引;洗掉name索引之后,才獲得上述截圖的效果,大家做實驗的時候需要注意,

到目前為止大家應該清楚了索引和回表帶來的性能問題,講這些自然不是為了恐嚇大家讓大家遠離索引,相反,我們要以正確的方式積極擁抱索引,最大限度降低其帶來的負面影響,放大其優勢,如何用好索引,從兩個方面考慮:

  1. 高效發揮已經創建的索引的作用(避免索引失效)
  2. 為合適的列創建合適的索引(索引創建原則)

4. 什么時候索引會失效?

4.1 違反最左前綴原則

拿我們文章開始創建的聯合索引為例,該聯合索引的B+樹資料頁內的記錄首先按照name欄位進行排序,name欄位相同的情況下,再按照phone欄位進行排序,

所以,如果我們直接使用phone欄位進行搜索,無法利用索引的順序性,

EXPLAIN SELECT * FROM user_innodb WHERE phone = "13203398311";

圖解|用好MySQL索引,你需要知道的一些事情

EXPLAIN可以查看搜索陳述句的執行計劃,其中,possible_keys串列示在當前查詢中,可能用到的索引有哪一些;key串列示實際用到的索引有哪一些,

但是一旦加上name的搜索條件,就會使用到聯合索引,而且不需要在意name在WHERE子句中的位置,因為查詢優化器會幫我們優化,

EXPLAIN SELECT * FROM user_innodb WHERE phone = "13203398311" AND name =
'蟬沐風';

圖解|用好MySQL索引,你需要知道的一些事情

4.2 使用反向查詢(!=, <>,NOT LIKE)

MySQL在使用反向查詢(!=, <>, NOT LIKE)的時候無法使用索引,會導致全表掃描,覆寫索引除外,

EXPLAIN SELECT * FROM user_innodb WHERE name != '蟬沐風';

圖解|用好MySQL索引,你需要知道的一些事情

4.3 LIKE以通配符開頭

當使用name LIKE '%沐風'或者name LIKE
'%沐%'這兩種方式都會使索引失效,因為聯合索引的B+樹資料頁內的記錄首先按照name欄位進行排序,這兩種搜索方式不在意name欄位的開頭是什么,自然就無法使用索引,只能通過全表掃描的方式進行查詢,

EXPLAIN SELECT * FROM user_innodb WHERE name LIKE '%沐風';

圖解|用好MySQL索引,你需要知道的一些事情

但是使用通配符結尾就沒有問題

EXPLAIN SELECT * FROM user_innodb WHERE name LIKE '蟬沐%';

圖解|用好MySQL索引,你需要知道的一些事情

4.4 對索引列做任何操作

如果不是單純使用索引列,而是對索引列做了其他操作,例如數值計算、使用函式、(手動或自動)型別轉換等操作,會導致索引失效,

4.4.1 使用函式

EXPLAIN SELECT * FROM user_innodb WHERE LEFT(name,3) = '蟬沐風';

圖解|用好MySQL索引,你需要知道的一些事情

MySQL8.0新增了函式索引的功能,我們可以給函式作用之后的結果創建索引,使用以下陳述句

ALTER TABLE user_innodb ADD KEY IDX_NAME_LEFT ((left(name,3)));

再次執行EXPLAIN陳述句,此時索引生效

圖解|用好MySQL索引,你需要知道的一些事情

4.4.2 使用運算式

EXPLAIN SELECT * FROM user_innodb WHERE id + 1 = 1100000;

圖解|用好MySQL索引,你需要知道的一些事情

換一種方式,單獨使用id,就能高效使用索引:

EXPLAIN SELECT * FROM user_innodb WHERE id = 1100000 - 1;

圖解|用好MySQL索引,你需要知道的一些事情

4.4.3 使用型別轉換

例1

user_innodb中的phone欄位為varchar型別,實驗之前我們先給phone欄位創建個索引

ALTER TABLE user_innodb ADD INDEX IDX_PHONE (phone);

隨便搜索一個存在的手機號,看一下索引是否成功

EXPLAIN SELECT * FROM user_innodb WHERE phone = '13203398311';

圖解|用好MySQL索引,你需要知道的一些事情

可以看到能使用到索引,現在我們稍微修改一下,把phone = '13203398311'修改為phone =
13203398311,這意味著我們將字串的搜索條件改成了整形的搜索條件,再看一下還會不會使用到索引:

EXPLAIN SELECT * FROM user_innodb WHERE phone = 13203398311;

圖解|用好MySQL索引,你需要知道的一些事情

顯示索引失效,

例2

我們再看一個例子,主鍵id型別是bigint,但是在搜索條件中我估計使用字串型別:

EXPLAIN SELECT * FROM user_innodb WHERE id = '1099999';

圖解|用好MySQL索引,你需要知道的一些事情

總結

稍微總結一下這個問題,當索引欄位型別為字串時,使用數字型別進行搜索不會用到索引;而索引欄位型別為數字型別時,使用字串型別進行搜索會使用到索引,

要搞明白這個問題,我們需要知道MySQL的資料型別轉換規則是什么,簡單地說就是MySQL會自動將數字轉化為字串,還是將字串轉化為數字,

一個簡單的方法是,通過SELECT '10' > 9的結果來確定MySQL的型別轉換規則:

  • 結果為1,說明MySQL會自動將字串型別轉化為數字,相當于執行了SELECT 10 > 9;
  • 結果為0,說明MySQL會自動將數字轉化為字串,相當于執行了SELECT '10' > '9',

mysql> SELECT '10' > 9;+----------+| '10' > 9 |+----------+| 1 |+----------+1
row in set (0.00 sec)

上面的執行結果為1,說明MySQL遇到型別轉換時,會自動將字串轉換為數字型別,因此對于例1:

EXPLAIN SELECT * FROM user_innodb WHERE phone = 13203398311;

就相當于

EXPLAIN SELECT * FROM user_innodb WHERE CAST(phone AS signed int) =
13203398311;

也就是對索引欄位使用了函式,按照前文的介紹,對索引使用函式是不會使用到索引的,

對于例2:

EXPLAIN SELECT * FROM user_innodb WHERE id = '1099999';

就相當于

EXPLAIN SELECT * FROM user_innodb WHERE id = CAST('1099999' AS unsigned int);

沒有在索引欄位添加任何操作,因此能夠使用到索引,

4.5 OR連接

使用OR連接的查詢陳述句,如果OR之前的條件列是索引列,但是OR之后的條件列不是索引列,則不會使用索引,舉例:

EXPLAIN SELECT * FROM user_innodb WHERE id = 1099999 OR gender = 0;

圖解|用好MySQL索引,你需要知道的一些事情

上面總結了一些索引失效的場景,這些經驗的總結往往對SQL的優化很有益處,但同時需要注意的是這些經驗并非金科玉律,

比如使用<>查詢時,在某些時候是可以用到索引的:

EXPLAIN SELECT * FROM user_innodb WHERE id <> 1099999;

圖解|用好MySQL索引,你需要知道的一些事情

最終是否使用索引,完全取決于MySQL的優化器,而優化器的判定依據就是cost開銷(Cost Base
Optimizer),優化器并非基于具體的規則,也不是基于語意,就是單純地執行開銷小的方案罷了,所以在·EXPLAIN·的結果中你會看到possible_keys一列,優化器會把這里邊的索引都試一遍(是不是又加深了對不能隨便創建索引的認識呢?),然后選一個開銷最小的,如果都不太行,那就直接全表掃描好了,

而cost開銷,和資料庫版本、資料量等都有關系,因此如果想更精準地提升索引功能性,擁抱EXPLAIN吧!

5. 索引創建(使用)原則

之前講過的 索引覆寫索引下推 都可以作為索引創建的原則,就是在創建索引的時候,盡量發揮 索引覆寫索引下推
的優勢,

盡量避免上述提及到的索引可能失效的情況的出現,同樣是索引的使用原則,

除此之外,再給大家介紹一些,

5.1 不為離散度高的列創建索引

先來看一下列的離散度公式:COUNT(DISTINCT(column_name)) /
COUNT(*),列的不重復值的個數與所有資料行的比例,簡而言之,如果列的重復值越多,列的離散度越低,重復值越少,離散度就越高,

舉個例子,gender(性別)列只有0、1兩個值,列的離散度非常低,假如我們為該列創建索引,我們會在二級索引中搜索到大量的重復資料,然后進行大量回表操作,大量回表哈?你懂了吧,

不要為重復值多的列創建索引

5.2 只為用于搜索、排序或分組的列創建索引

我們只為出現在WHERE子句中的列或者出現在ORDER BY和GROUP BY子句中的列創建索引即可,僅出現在查詢串列中的列不需要創建索引,

5.3 用好聯合索引

用2條SQL陳述句來說明這個問題:

1. SELECT * FROM user_innodb WHERE name = '蟬沐風' AND phone = '13203398311';2.
SELECT * FROM user_innodb WHERE name = '蟬沐風';

陳述句1和陳述句2都能夠使用索引,這帶給我們的一個索引設計原則就是:

不要為聯合索引的第一個索引列單獨創建索引

因為聯合索引本身就是先按照name列進行排序,因此聯合索引對name的搜索是有效的,不需要單獨為name再創建索引了,也正因為此

建立聯合索引的時候,一定要把最常用的列放在最左邊

5.4 對過長的欄位,建立前綴索引

如果一個字串格式的列占用的空間比較大(就是說允許存盤比較長的字串資料),為該列創建索引,就意味著該列的資料會被完整地記錄在每個資料頁的每條記錄中,會占用相當大的存盤空間,

對此,我們可以為該列的前幾個字符創建索引,也就是在二級索引的記錄中只會保留字串的前幾個字符,比如我們可以為phone列創建索引,索引只保留手機號的前3位:

ALTER TABLE user_innodb ADD INDEX IDX_PHONE_3 (phone(3));

然后執行下面的SQL陳述句:

EXPLAIN SELECT * FROM user_innodb WHERE phone = '1320';

圖解|用好MySQL索引,你需要知道的一些事情

由于在IDX_PHONE_3索引中只保留了手機號的前3位數字,所以我們只能定位到以132開頭的二級索引記錄,然后在遍歷所有的這些二級索引記錄時再判斷它們是否滿足第4位數為0的條件,

當列中存盤的字串包含的字符較多時,為該欄位建立前綴索引可以有效節省磁盤空間

5.5 頻繁更新的值,不要作為主鍵或索引

因為可能涉及到資料頁分裂的情況,會影響性能,

5.6 隨機無序的值,不建議作為索引,例如身份證、UUID

不建議作為索引,例如身份證、UUID

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/467099.html

標籤:MySQL

上一篇:面試官:請用SQL模擬一個死鎖

下一篇:Redis設計與實作2.1:主從復制

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more