您的位置:首頁(yè) > 軟件教程 > 教程 > count(*)、count(1)哪個(gè)更快?面試必問:通宵整理的十道經(jīng)典MySQL必問面試題

count(*)、count(1)哪個(gè)更快?面試必問:通宵整理的十道經(jīng)典MySQL必問面試題

來源:好特整理 | 時(shí)間:2024-10-21 09:45:56 | 閱讀:97 |  標(biāo)簽: T S C 面試 經(jīng)典   | 分享到:

一、你是如何理解Count(*)和Count(1)的? 這兩個(gè)并沒有區(qū)別,不要覺得 count() 會(huì)查出全部字段,而 count(1) 不會(huì)。所以 count() 會(huì)更慢,你覺得 MySQL 作者會(huì)這么做嗎? 可以很明確地告訴你們 count() 和 count(1) 是一樣的,而正確有區(qū)別的是

一、你是如何理解Count(*)和Count(1)的?

這兩個(gè)并沒有區(qū)別,不要覺得 count( ) 會(huì)查出全部字段,而 count(1) 不會(huì)。所以 count( ) 會(huì)更慢,你覺得 MySQL 作者會(huì)這么做嗎?

可以很明確地告訴你們 count( ) 和 count(1) 是一樣的,而正確有區(qū)別的是 count(字段)。如果你 count() 的是具體的字段,那么 MySQL 會(huì)判斷某行記錄中對(duì)應(yīng)字段是否為 null,如果為 null 就不會(huì)進(jìn)行統(tǒng)計(jì)了。因此 count(字段) 的結(jié)果可能會(huì)小于 count( ) 和 count(1)。

另外,直接執(zhí)行 select (*) from t1; 時(shí),也可以利用到索引的,并不一定是全表掃描,也可以掃描某個(gè)索引 B+ 樹的葉子節(jié)點(diǎn),從而得到總條數(shù),因?yàn)椴还苁鞘裁此饕麈I索引還是輔助索引,實(shí)際上它們?cè)谌~子節(jié)點(diǎn)的數(shù)量是一樣的,只不過字段數(shù)不一樣,主鍵索引存了全部字段,而輔助索引只存了定義的索引字段 + 主鍵字段,所以通常輔助索引是更占用空間的,因此遍歷起來也會(huì)更快,但是記錄條數(shù)是一樣的。

二、你是如何理解最左前綴原則的?

這個(gè)原則表明,只有在復(fù)合索引的左側(cè)部分的列上,條件才能被優(yōu)化。換句話說,當(dāng)使用復(fù)合索引時(shí),查詢的條件應(yīng)該從索引的最左側(cè)列開始,才能最大化利用索引

我們創(chuàng)建一個(gè)簡(jiǎn)單的示例表,命名為 employees ,并在其上創(chuàng)建一個(gè)復(fù)合索引。表結(jié)構(gòu)如下:

CREATE TABLE employees (
    id INT AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    age INT,
    department VARCHAR(50),
    INDEX idx_name_age (last_name, first_name, age)
);

接下來,我們插入一些實(shí)例數(shù)據(jù)

INSERT INTO employees (first_name, last_name, age, department) VALUES
('John', 'Doe', 30, 'HR'),
('Jane', 'Doe', 25, 'IT'),
('Mary', 'Smith', 35, 'Finance'),
('Michael', 'Johnson', 40, 'IT'),
('Emily', 'Davis', 29, 'HR');

符合最左前綴原則的查詢SQL

SELECT * FROM employees WHERE last_name = 'Doe' AND first_name = 'Jane' AND age=25;
SELECT * FROM employees WHERE  first_name = 'Jane' AND last_name = 'Doe' AND age=30;
SELECT * FROM employees WHERE  age=30 AND last_name = 'Doe' AND first_name = 'Jane';

對(duì)于上面這些查詢,MySQL會(huì)使用idx_name_age索引,從這能夠看出,以上SQL都能走索引,和Where條件順序沒有關(guān)系

+----+-------------+-----------+-------+---------------+---------+---------+------+-------+-------------+
| id | select_type | table     | type  | possible_keys | key     | key_len | ref  | rows  | Extra       |
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+-------------+
|  1 | SIMPLE      | employees | range | idx_name_age  | idx_name_age | 100     | NULL |     2 | Using where |
+----+-------------+-----------+-------+---------------+---------+---------+------+-------+-------------+

在這個(gè)執(zhí)行計(jì)劃中,我們看到type是range,說明MySQL正在使用idx_name_age索引,并且只檢查了大約2行數(shù)據(jù)。

那如果把last_name去掉呢?

不符合最左前綴原則的查詢

SELECT * FROM employees WHERE first_name = 'Jane' AND age = 25;

對(duì)于這個(gè)查詢,MySQL不會(huì)使用復(fù)合索引idx_name_age,因?yàn)樗鼪]有從最左側(cè)的列l(wèi)ast_name開始。

通過Explain執(zhí)行計(jì)劃,查看索引執(zhí)行情況

+----+-------------+-----------+-------+---------------+------+---------+------+-------+-------------+
| id | select_type | table     | type  | possible_keys | key  | key_len | ref  | rows  | Extra       |
+----+-------------+-----------+-------+---------------+------+---------+------+-------+-------------+
|  1 | SIMPLE      | employees | ALL   | NULL          | NULL | NULL    | NULL |     5 | Using where |
+----+-------------+-----------+-------+---------------+------+---------+------+-------+-------------+

在這個(gè)執(zhí)行計(jì)劃中,我們看到type是ALL,這意味著MySQL沒有使用任何索引,而是進(jìn)行了全表掃描,這樣效率較低。

最近無意間獲得一份阿里大佬寫的刷題筆記,一下子打通了我的任督二脈,進(jìn)大廠原來沒那么難。這是大佬寫的, 7701頁(yè)的BAT大佬寫的刷題筆記,讓我offer拿到手軟

總結(jié)

從這可以看出,所謂的最左前綴原則的“最左”,并不是指where條件中的last_name一定要在最左邊,而是指where條件中一定要給出定義聯(lián)合索引的最左邊字段,比如我們定義“l(fā)ast_name, first_name, age”聯(lián)合索引的SQL為:

INDEX idx_name_age (last_name, first_name, age)

其中l(wèi)ast_name字段是最左邊的字段,因此如果想要走idx_name_age索引,那么SQL一定要給出last_name字段的條件,這才是“最左”的意思。

三、你是如何理解行鎖、GAP鎖、臨健鎖的?

1、行數(shù)

行鎖是對(duì)具體數(shù)據(jù)行的鎖定,允許多個(gè)事務(wù)并發(fā)操作不同行,只有在同一行上進(jìn)行寫入時(shí)才會(huì)阻塞其他事務(wù)

假設(shè)我們有如下表結(jié)構(gòu)和數(shù)據(jù):

CREATE TABLE employees (
    id INT AUTO_INCREMENT PRIMARY KEY,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    age INT,
    department VARCHAR(50)
);

如果事務(wù)A更新了某個(gè)特定員工的信息:

-- 事務(wù)A
START TRANSACTION;
UPDATE employees SET age = 31 WHERE last_name = 'Doe';

在這個(gè)過程中,行鎖會(huì)被加在last_name = 'Doe'所對(duì)應(yīng)的行上(即John和Jane)。如果此時(shí)事務(wù)B嘗試更新同一行:

-- 事務(wù)B
START TRANSACTION;
UPDATE employees SET age = 29 WHERE last_name = 'Doe';

事務(wù)B會(huì)被阻塞,直到事務(wù)A提交或回滾,因?yàn)槭聞?wù)A、事務(wù)B加的都是排它鎖,也叫悲觀鎖。這樣行鎖確保了數(shù)據(jù)的一致性。

GAP鎖

行鎖鎖的是某一行,而GAP鎖鎖的是行前面的間隙,注意只是行前面的間隙,你可能會(huì)問那表的最后一行前后都有間隙啊,最后一行后面的間隙不鎖嗎?

當(dāng)然會(huì)鎖了,只不,過是交給了一個(gè)叫做PAGE_NEW_SUPREMUM的記錄來說,你可以理解為PAGE_NEW_SUPREMUM記錄是InnoDB默認(rèn)的,它固定作為最后一條記錄,因此只要鎖住PAGE_NEW_SUPREMUM前面的間隙,就相當(dāng)于鎖住了我們所理解的最后一行后面的間隙。

count(*)、count(1)哪個(gè)更快?面試必問:通宵整理的十道經(jīng)典MySQL必問面試題

臨健鎖(Next-Key Lock)

臨界鎖是行鎖和GAP鎖的結(jié)合,鎖定具體的數(shù)據(jù)行以及行之間的空隙。它用于確保在一個(gè)范圍內(nèi)的查詢中,不僅防止了幻讀,還能保護(hù)行數(shù)據(jù)

繼續(xù)使用之前的例子,假設(shè)我們執(zhí)行了如下操作:

-- 事務(wù)D
START TRANSACTION;
SELECT * FROM employees WHERE last_name >= 'D' FOR UPDATE;

在此查詢中,MySQL會(huì)對(duì)所有l(wèi)ast_name為'D'及其后的行加上行鎖,同時(shí)對(duì)'D'之前的空隙加上GAP鎖,這樣可以防止在該范圍內(nèi)插入新的行。

四、你是如何理解MVCC的?

OCR識(shí)別結(jié)果出現(xiàn)了一些錯(cuò)誤和混亂,導(dǎo)致內(nèi)容不夠清晰。雖然識(shí)別不是很理想,但我將根據(jù)我的理解和相關(guān)知識(shí),概述該圖片可能傳達(dá)的內(nèi)容。

如何理解MVCC?

所謂MVCC就是多版本并發(fā)控制,MySQL為了實(shí)現(xiàn)可重復(fù)讀這個(gè)隔離級(jí)別,而且為了不采用鎖機(jī)制來實(shí)現(xiàn)可重復(fù)讀,所以采用MVCC機(jī)制來實(shí)現(xiàn)。

主要概念

  1. ReadView(讀取視圖)

    • 當(dāng)一個(gè)事務(wù)開始時(shí),MVCC會(huì)創(chuàng)建一個(gè) ReadView ,該視圖記錄了當(dāng)前可見的所有版本,包括哪些事務(wù)是活躍的,哪些事務(wù)已經(jīng)提交。
  2. 事務(wù)ID

    • 每個(gè)事務(wù)都有一個(gè)唯一的事務(wù)ID。在 ReadView 中,會(huì)記錄當(dāng)前事務(wù)的ID、最小事務(wù)ID和最大事務(wù)ID。
  3. 可見性規(guī)則

    • 如果一個(gè)事務(wù)的ID
      1. 大于 ReadView 中的最大事務(wù)ID:這個(gè)事務(wù)的更改對(duì)當(dāng)前事務(wù)不可見。
      2. 屬于 ReadView 中的活躍事務(wù):則該事務(wù)的更改不可見,因?yàn)樵撌聞?wù)還在進(jìn)行中。
      3. 小于 ReadView 中的最小事務(wù)ID:該事務(wù)的更改是可見的,因?yàn)樗呀?jīng)提交。

MVCC的工作流程

  • 創(chuàng)建 ReadView

    • 當(dāng)事務(wù)開始時(shí),MVCC會(huì)生成一個(gè) ReadView 。它會(huì)包含當(dāng)前事務(wù)的ID、活躍事務(wù)的ID以及最大和最小事務(wù)ID。
  • 讀取數(shù)據(jù)

    • 當(dāng)事務(wù)讀取數(shù)據(jù)時(shí),它將參考 ReadView 中的信息,以確定哪些版本的數(shù)據(jù)是可見的。
  • 更新數(shù)據(jù)

    • 當(dāng)事務(wù)更新數(shù)據(jù)時(shí),MVCC不會(huì)直接覆蓋原有的數(shù)據(jù),而是創(chuàng)建一個(gè)新的版本。只有在所有引用該數(shù)據(jù)的事務(wù)完成后,才會(huì)清理舊版本。

count(*)、count(1)哪個(gè)更快?面試必問:通宵整理的十道經(jīng)典MySQL必問面試題

總結(jié)

MVCC允許多個(gè)事務(wù)在不干擾彼此的情況下同時(shí)進(jìn)行操作,這極大地提高了數(shù)據(jù)庫(kù)的并發(fā)性能。通過維護(hù)數(shù)據(jù)的多個(gè)版本,MVCC保證了數(shù)據(jù)的一致性和隔離性,同時(shí)減少了鎖的競(jìng)爭(zhēng)。

最近無意間獲得一份阿里大佬寫的刷題筆記,一下子打通了我的任督二脈,進(jìn)大廠原來沒那么難。這是大佬寫的, 7701頁(yè)的BAT大佬寫的刷題筆記,讓我offer拿到手軟

五、你是如何理解Online DDL的?

Online DDL 是指在不影響數(shù)據(jù)庫(kù)服務(wù)的情況下,修改數(shù)據(jù)庫(kù)表的結(jié)構(gòu)。通俗點(diǎn)說,就是我們可以在數(shù)據(jù)庫(kù)正常運(yùn)作的同時(shí),對(duì)表進(jìn)行調(diào)整,比如新增列、修改字段類型、添加索引等,而不需要停機(jī)維護(hù)。

般的DDL操作,比如新增一個(gè)字段,會(huì)有以下幾個(gè)步驟

1. 解析與檢查

MySQL 首先會(huì)對(duì) DDL 語(yǔ)句進(jìn)行解析,確保語(yǔ)法正確。例如:

ALTER TABLE users ADD COLUMN age INT;

MySQL 會(huì)檢查表 users 是否存在,新增的 age 字段是否與已有的字段沖突(比如字段名重復(fù)),數(shù)據(jù)類型是否支持等。

2. 表的元數(shù)據(jù)鎖(metadata lock)

在進(jìn)行任何表結(jié)構(gòu)變更之前,MySQL 會(huì)對(duì)表加一個(gè)元數(shù)據(jù)鎖(MDL)。元數(shù)據(jù)鎖的作用是防止在變更結(jié)構(gòu)的同時(shí),其他 DDL 操作對(duì)表進(jìn)行修改,保證表結(jié)構(gòu)一致性。

類比 :元數(shù)據(jù)鎖就像在超市里裝貨架時(shí),防止其他人也來同時(shí)更改貨架位置,避免混亂。

3. 創(chuàng)建臨時(shí)表

當(dāng)我們執(zhí)行 ALTER TABLE 語(yǔ)句時(shí),MySQL 會(huì)創(chuàng)建一個(gè) 臨時(shí)表 。這個(gè)臨時(shí)表是現(xiàn)有表的一個(gè)復(fù)制品,并且會(huì)按照我們的要求增加新的字段。

臨時(shí)表的步驟:

  1. 復(fù)制原表結(jié)構(gòu) :MySQL 會(huì)復(fù)制原表的結(jié)構(gòu)到一個(gè)臨時(shí)表中,并加上我們新增的字段,比如 age 。
  2. 復(fù)制數(shù)據(jù) :MySQL 將原表中的所有數(shù)據(jù)行逐行復(fù)制到臨時(shí)表中,同時(shí)為每一行填充新增加字段的默認(rèn)值(如果有)。

類比 :這就像超市貨架升級(jí)時(shí),先在倉(cāng)庫(kù)里搭建一個(gè)新的貨架模型,放置相同的商品,同時(shí)增加新的商品存放區(qū)。

4. 切換表

當(dāng) MySQL 完成了數(shù)據(jù)復(fù)制后,它會(huì)將原表和臨時(shí)表進(jìn)行替換。此時(shí),臨時(shí)表變成了正式的表,包含了新字段。

  • 在這個(gè)過程中,所有的 DML(增刪改查)操作都會(huì)暫時(shí)被掛起,直到替換完成。這段時(shí)間很短暫,對(duì)服務(wù)的影響非常小。

類比 :就像倉(cāng)庫(kù)里的新貨架搭建好后,把它搬進(jìn)超市,同時(shí)替換掉舊貨架。顧客幾乎不會(huì)察覺到這個(gè)過程。

5. 刪除舊表

原始的表被新表替換后,MySQL 會(huì)自動(dòng)刪除舊表的元數(shù)據(jù),釋放空間。這一步在后臺(tái)完成,不影響數(shù)據(jù)庫(kù)的正常操作。

6. 釋放鎖

當(dāng)所有操作完成后,MySQL 會(huì)釋放元數(shù)據(jù)鎖,允許其他 DDL 或 DML 操作繼續(xù)進(jìn)行。

總結(jié):

  1. 解析語(yǔ)句并檢查合法性。
  2. 對(duì)表加元數(shù)據(jù)鎖(防止沖突的結(jié)構(gòu)變更)。
  3. 創(chuàng)建臨時(shí)表,并將數(shù)據(jù)從舊表復(fù)制到臨時(shí)表。
  4. 替換舊表,刪除舊表的元數(shù)據(jù)。
  5. 釋放鎖。

注意 :這種方法在 不使用 Online DDL 的情況下,可能導(dǎo)致大量的數(shù)據(jù)復(fù)制操作,進(jìn)而對(duì)性能有影響,尤其是表數(shù)據(jù)量較大時(shí)。

六、你知道哪些情況下會(huì)導(dǎo)致索引失效

在 MySQL 中,索引是提高查詢效率的關(guān)鍵工具,但有時(shí)可能會(huì)遇到索引 失效 的情況,導(dǎo)致查詢性能大幅下降。這種情況通常與查詢語(yǔ)句的寫法、數(shù)據(jù)類型的選擇以及數(shù)據(jù)庫(kù)的優(yōu)化機(jī)制有關(guān)。下面是幾種常見會(huì)導(dǎo)致索引失效的場(chǎng)景:

1. 使用 LIKE 時(shí)通配符放在前面

如果在 LIKE 語(yǔ)句中,通配符 % 放在字符串的開頭,會(huì)導(dǎo)致索引失效。因?yàn)樵谶@種情況下,MySQL 無法通過索引快速定位到符合條件的記錄,而需要掃描所有記錄。

示例:

SELECT * FROM users WHERE name LIKE '%abc';  -- 索引失效

這種寫法會(huì)使得 MySQL 掃描全表,而如果寫成 LIKE 'abc%' ,索引仍然有效。

類比 :這就像你在一大堆文件中查找名字以"abc"開頭的文件名,你可以直接找到相應(yīng)的部分,但如果是查找名字包含"abc"的文件,你就得看每個(gè)文件名。

2. 數(shù)據(jù)類型不一致

當(dāng)查詢條件中的字段類型與索引字段的類型不一致時(shí),MySQL 可能不會(huì)使用索引。它會(huì)先對(duì)數(shù)據(jù)進(jìn)行類型轉(zhuǎn)換,而類型轉(zhuǎn)換會(huì)導(dǎo)致無法高效利用索引。

示例:

假設(shè) id 是一個(gè)整型字段:

SELECT * FROM users WHERE id = '123';  -- 索引失效

這里的 '123' 是字符串,MySQL 會(huì)進(jìn)行隱式轉(zhuǎn)換,因此索引失效。

3. 對(duì)索引字段使用函數(shù)

如果在查詢中對(duì)索引字段使用了函數(shù)或運(yùn)算操作,MySQL 不能通過索引來查詢,導(dǎo)致索引失效。

示例:

SELECT * FROM users WHERE YEAR(created_at) = 2023;  -- 索引失效

這里 YEAR(created_at) 是對(duì) created_at 字段進(jìn)行了函數(shù)操作,因此 MySQL 無法直接使用索引進(jìn)行查找。

類比 :這就像你想按某種規(guī)律排列的列表中查找內(nèi)容,但你需要先改變它的形式才能找到,導(dǎo)致效率下降。

4. 使用 OR 關(guān)鍵字

當(dāng) OR 條件中的某一列沒有索引時(shí),整個(gè)查詢的索引都會(huì)失效。

示例:

SELECT * FROM users WHERE id = 1 OR name = 'Alice';  -- 索引失效

假設(shè) id 列有索引,而 name 列沒有索引,那么這個(gè)查詢就不能利用索引,MySQL 需要進(jìn)行全表掃描。

優(yōu)化方式 :為 name 字段單獨(dú)建立索引,或者改寫查詢邏輯,避免 OR 導(dǎo)致的索引失效。

5. 不等條件 ( != <> )

使用不等于操作符( != <> )時(shí),MySQL 不能有效使用索引,會(huì)導(dǎo)致全表掃描。

示例:

SELECT * FROM users WHERE age != 30;  -- 索引失效

這類查詢通常會(huì)導(dǎo)致索引失效,因?yàn)?MySQL 無法通過索引定位所有滿足 != 的記錄。

6. 范圍查詢 ( > , < , BETWEEN ) 后的列

在復(fù)合索引(即多列索引)中,當(dāng)?shù)谝粋(gè)字段使用了范圍查詢時(shí),后續(xù)的字段的索引可能會(huì)失效。

示例:

假設(shè)我們有一個(gè)復(fù)合索引 (age, name) ,如下查詢:

SELECT * FROM users WHERE age > 30 AND name = 'Alice';  -- `name` 索引失效

在這種情況下,由于 age 使用了范圍查詢, name 列的索引將失效,MySQL 無法通過復(fù)合索引直接查找。

7. 索引列前加上 IS NULL IS NOT NULL

對(duì)于索引列使用 IS NULL IS NOT NULL ,有時(shí) MySQL 可能不會(huì)利用索引,尤其是在大量數(shù)據(jù)存在 NULL 值的情況下,MySQL 會(huì)認(rèn)為索引的使用不劃算。

示例:

SELECT * FROM users WHERE name IS NOT NULL;  -- 可能索引失效

8. 查詢條件中使用 NOT IN NOT EXISTS

使用 NOT IN NOT EXISTS 也可能會(huì)導(dǎo)致 MySQL 不使用索引,從而引發(fā)全表掃描。

示例:

SELECT * FROM users WHERE id NOT IN (1, 2, 3);  -- 索引失效

9. 表中的數(shù)據(jù)量很小

當(dāng)表中的數(shù)據(jù)量很小,MySQL 可能認(rèn)為全表掃描比使用索引更高效。在這種情況下,MySQL 會(huì)選擇直接掃描而不是通過索引查找。

類比 :如果你只有幾個(gè)文件需要查找,花時(shí)間先創(chuàng)建目錄索引反而不劃算,直接掃描全部文件更快。

10. MySQL 優(yōu)化器選擇不使用索引

有時(shí),即便索引可用,MySQL 的查詢優(yōu)化器可能會(huì)根據(jù)表的統(tǒng)計(jì)信息和成本估算,認(rèn)為全表掃描比使用索引更快,從而放棄索引。

總結(jié):

索引失效通常與查詢語(yǔ)句的寫法、數(shù)據(jù)類型、函數(shù)使用、以及 MySQL 查詢優(yōu)化器的決策有關(guān)。為了避免索引失效,需要盡量避免上述常見的情況,如:

  • LIKE 查詢中避免通配符 % 開頭
  • 保持?jǐn)?shù)據(jù)類型一致
  • 盡量不對(duì)索引列使用函數(shù)或運(yùn)算操作
  • 合理規(guī)劃復(fù)合索引中的查詢順序

七、你是如何理解MySQL的filesort的?

通俗的理解,可以把 filesort 理解為數(shù)據(jù)庫(kù)的“備用排序方式”。當(dāng)查詢中的 ORDER BY 語(yǔ)句無法利用索引中的排序順序時(shí),MySQL 就會(huì)啟用 filesort 來手動(dòng)排序結(jié)果。

什么時(shí)候會(huì)觸發(fā) filesort ?

MySQL 會(huì)在某些情況下使用 filesort ,比如:

  1. 沒有合適的索引
    當(dāng)查詢中的 ORDER BY 字段沒有索引,MySQL 無法利用索引順序,只能借助 filesort 來進(jìn)行排序。

    示例:

    SELECT * FROM users ORDER BY age;
    

    假設(shè) users 表中沒有 age 字段的索引,這時(shí)候 MySQL 會(huì)進(jìn)行 filesort 。

  2. 多列排序,但索引不匹配
    當(dāng)我們對(duì)多個(gè)列進(jìn)行排序,而這些列沒有被索引覆蓋或索引順序與排序要求不符時(shí), filesort 也會(huì)被觸發(fā)。

    示例:

    SELECT * FROM users ORDER BY age, name;
    

    假設(shè)表上只有 age 的索引,但沒有 (age, name) 的復(fù)合索引,那么 MySQL 會(huì)使用 filesort 。

  3. 組合查詢或函數(shù)操作導(dǎo)致索引失效
    當(dāng)查詢中對(duì)字段進(jìn)行計(jì)算或函數(shù)操作時(shí),即便這些字段有索引,也無法直接利用索引進(jìn)行排序。

    示例:

    SELECT * FROM users ORDER BY LENGTH(name);
    

    LENGTH(name) 是一個(gè)函數(shù)操作,MySQL 需要手動(dòng)排序,因此會(huì)使用 filesort

filesort 的工作方式:

filesort 實(shí)際上有兩種實(shí)現(xiàn)方式,取決于 MySQL 的版本和配置:

  1. 單行數(shù)據(jù)排序 (Older Versions):MySQL 會(huì)把查詢結(jié)果的所有行都放入一個(gè)緩沖區(qū),然后根據(jù) ORDER BY 字段逐行比較并排序。這種方式效率相對(duì)較低,因?yàn)橐幚淼臄?shù)據(jù)量很大。

  2. 兩次掃描排序 (Optimized Versions):在較新的 MySQL 版本中, filesort 會(huì)進(jìn)行優(yōu)化,只會(huì)在第一次掃描時(shí)收集需要排序的字段和 ROW_ID ,然后通過排序后的 ROW_ID 再去讀取整行數(shù)據(jù)。這種方式減少了排序的數(shù)據(jù)量,提高了性能。

filesort 性能的影響:

filesort 并不是說每次都會(huì)涉及磁盤操作,它有可能在內(nèi)存中完成,但當(dāng)數(shù)據(jù)量較大時(shí),內(nèi)存不足以完成排序,就可能將數(shù)據(jù)寫入磁盤進(jìn)行排序,這樣會(huì)影響性能。

MySQL 有兩個(gè)重要的參數(shù)控制 filesort 行為:

  1. sort_buffer_size :這是 MySQL 用來在內(nèi)存中排序的緩沖區(qū)大小。如果排序的數(shù)據(jù)能放進(jìn)這個(gè)緩沖區(qū),排序就會(huì)在內(nèi)存中完成;否則,MySQL 會(huì)將部分?jǐn)?shù)據(jù)寫入磁盤,從而影響性能。

  2. max_length_for_sort_data :控制 MySQL 采用哪種 filesort 方法(單行排序或兩次掃描排序)。對(duì)于較短的數(shù)據(jù),MySQL 更可能選擇效率較高的兩次掃描排序方式。

如何避免或優(yōu)化 filesort ?

  1. 使用合適的索引
    最直接的辦法就是為查詢中的排序字段創(chuàng)建索引。尤其是在有 ORDER BY 子句時(shí),確保創(chuàng)建了復(fù)合索引可以有效避免 filesort 。

    示例:

    CREATE INDEX idx_age_name ON users (age, name);
    
  2. 增加 sort_buffer_size
    如果無法避免 filesort ,可以通過增加 sort_buffer_size 的大小,確保更多數(shù)據(jù)可以在內(nèi)存中排序,減少磁盤 I/O。

  3. 減少排序的數(shù)據(jù)量
    使用 LIMIT 來限制查詢結(jié)果集的大小,可以減少需要排序的數(shù)據(jù)量,從而減小 filesort 的開銷。

    示例:

    SELECT * FROM users ORDER BY age LIMIT 100;
    
  4. 盡量避免對(duì)排序字段使用函數(shù)
    ORDER BY 中,盡量不要對(duì)排序字段進(jìn)行函數(shù)運(yùn)算或表達(dá)式操作,這樣可以增加 MySQL 使用索引的可能性。

總結(jié):

filesort 是 MySQL 中的一種排序機(jī)制,當(dāng)查詢結(jié)果無法通過索引順序排序時(shí),MySQL 就會(huì)啟用 filesort 進(jìn)行手動(dòng)排序。雖然名字中有“file”,但排序未必一定涉及磁盤操作,內(nèi)存中的排序也是常見的。 filesort 是 MySQL 的備用排序方式,盡管有時(shí)不可避免,但我們可以通過創(chuàng)建索引、調(diào)整緩沖區(qū)大小等方式來優(yōu)化它的性能。

八、你知道哪些情況下會(huì)鎖表嗎?

一、常見的鎖表情況

1. DDL 操作(數(shù)據(jù)定義語(yǔ)言)

當(dāng)執(zhí)行一些結(jié)構(gòu)性變更的操作(例如 ALTER TABLE CREATE TABLE 、 DROP TABLE )時(shí),MySQL 會(huì)鎖住整個(gè)表,防止其他線程對(duì)該表進(jìn)行操作。這種鎖是 元數(shù)據(jù)鎖 (Metadata Lock),用來保證表結(jié)構(gòu)的變更不會(huì)與其他并發(fā)操作發(fā)生沖突。

示例:

ALTER TABLE users ADD COLUMN age INT;

此操作會(huì)鎖表,其他對(duì) users 表的操作會(huì)被阻塞,直到變更完成。

2. 全表掃描的 UPDATE DELETE 操作

當(dāng)你執(zhí)行一個(gè) UPDATE DELETE 操作且未使用索引時(shí),MySQL 可能會(huì)鎖住整個(gè)表進(jìn)行更新或刪除,因?yàn)樗仨殥呙杷行小?

示例:

UPDATE users SET age = 30 WHERE name LIKE '%John%';  -- 如果沒有索引,可能鎖表

由于 LIKE '%John%' 無法利用索引,MySQL 需要全表掃描,并對(duì)整個(gè)表加鎖。

3. 事務(wù)中的寫操作( INSERT UPDATE 、 DELETE

在 InnoDB 存儲(chǔ)引擎中,寫操作會(huì)對(duì)數(shù)據(jù)行加上 行鎖 (Row Lock)。但是在某些情況下(如沒有索引的情況下),MySQL 可能會(huì)退化為 表鎖 (Table Lock)。即使是行鎖,在長(zhǎng)事務(wù)未提交或回滾的情況下,也可能阻塞其他事務(wù),從而產(chǎn)生間接的鎖表現(xiàn)象。

示例:

BEGIN;
UPDATE orders SET status = 'shipped' WHERE order_id = 1234;  -- 行鎖,但可能鎖表
COMMIT;

如果該事務(wù)運(yùn)行了很長(zhǎng)時(shí)間,并且其他操作也需要訪問 orders 表中的記錄,可能會(huì)導(dǎo)致等待。

4. LOCK TABLES 顯式加鎖

MySQL 支持使用 LOCK TABLES 命令顯式地對(duì)表加鎖,分為 讀鎖(READ LOCK) 寫鎖(WRITE LOCK) 。在寫鎖期間,其他線程不能對(duì)該表進(jìn)行任何讀或?qū)懖僮;在讀鎖期間,其他線程只能讀表,而不能寫表。

示例:

LOCK TABLES users WRITE;  -- 對(duì) `users` 表加寫鎖

此時(shí),其他線程對(duì) users 表的任何讀寫操作都會(huì)被阻塞,直到鎖被釋放。

5. 大批量插入數(shù)據(jù)

當(dāng)你使用某些批量插入語(yǔ)句(如 INSERT INTO ... SELECT ... INSERT IGNORE )插入大量數(shù)據(jù)時(shí),如果沒有恰當(dāng)?shù)乃饕琈ySQL 可能會(huì)鎖表,尤其是在 MyISAM 存儲(chǔ)引擎中。

示例:

INSERT INTO new_users SELECT * FROM users WHERE created_at > '2023-01-01';  -- 可能鎖表

如果 created_at 沒有索引,MySQL 需要鎖表來完成整個(gè)插入操作。

6. 外鍵約束檢查

在 InnoDB 中,當(dāng)插入或刪除涉及到外鍵約束的數(shù)據(jù)時(shí),MySQL 可能會(huì)鎖住父表或子表,確保數(shù)據(jù)的完整性。雖然 InnoDB 大多情況下會(huì)使用行鎖,但在某些復(fù)雜的情況下,比如沒有合適的索引,可能會(huì)導(dǎo)致表鎖。

示例:

DELETE FROM orders WHERE order_id = 100;  -- 觸發(fā)外鍵約束檢查,可能鎖住 `customers` 表

如果 orders 表有外鍵關(guān)聯(lián)到 customers 表,且沒有合適的索引,可能會(huì)鎖住 customers 表。

7. MyISAM 存儲(chǔ)引擎的讀寫操作

在 MyISAM 存儲(chǔ)引擎中,寫操作會(huì)鎖住整個(gè)表,即使只修改了一行。讀操作之間不會(huì)互相阻塞,但讀寫操作之間會(huì)發(fā)生阻塞。因此,MyISAM 表在處理高并發(fā)寫操作時(shí)可能會(huì)頻繁鎖表。

示例:

INSERT INTO myisam_table (name, age) VALUES ('John', 30);  -- 寫鎖鎖住整個(gè)表

如果有大量的寫操作,表會(huì)頻繁被鎖住,影響并發(fā)性能。

二、如何避免鎖表?

鎖表會(huì)影響數(shù)據(jù)庫(kù)的并發(fā)性和性能,因此我們通常需要盡量避免。這里有一些方法可以減少鎖表的發(fā)生:

1. 使用合適的存儲(chǔ)引擎

盡量使用 InnoDB 存儲(chǔ)引擎,它支持 行級(jí)鎖 ,可以在絕大多數(shù)情況下避免鎖表。相比之下, MyISAM 使用的是 表級(jí)鎖 ,在并發(fā)讀寫場(chǎng)景下性能較差。

2. 創(chuàng)建合適的索引

通過為查詢條件中的列創(chuàng)建適當(dāng)?shù)乃饕苊馊頀呙琛@,如果你?jīng)常根據(jù) name 字段進(jìn)行查詢和更新,應(yīng)該為 name 字段創(chuàng)建索引:

CREATE INDEX idx_name ON users (name);

索引可以有效減少鎖表的可能性。

3. 減少長(zhǎng)事務(wù)

長(zhǎng)時(shí)間未提交的事務(wù)會(huì)持有鎖,從而阻塞其他查詢。因此,盡量縮短事務(wù)的執(zhí)行時(shí)間,確保在事務(wù)中盡快完成操作并提交。

4. 使用 OPTIMIZE ANALYZE 慎重

這些命令會(huì)鎖住表的元數(shù)據(jù),阻止并發(fā)的讀寫操作。運(yùn)行這些命令時(shí)應(yīng)避免高并發(fā)時(shí)間段。

5. 分批次操作

如果需要執(zhí)行大量的 UPDATE DELETE ,可以將操作分批執(zhí)行,以減少每次操作涉及的數(shù)據(jù)量,避免長(zhǎng)時(shí)間鎖表。

示例:

DELETE FROM users WHERE created_at < '2022-01-01' LIMIT 1000;  -- 分批刪除

6. 避免顯式表鎖

盡量避免使用 LOCK TABLES 進(jìn)行顯式加鎖操作,尤其是在高并發(fā)場(chǎng)景下。InnoDB 的事務(wù)機(jī)制和行級(jí)鎖已經(jīng)足夠應(yīng)對(duì)大多數(shù)并發(fā)問題。

九、你是如何理解MySQL中的死鎖機(jī)制的?

在 MySQL 中, 死鎖 (Deadlock)是指兩個(gè)或多個(gè)事務(wù)互相等待對(duì)方持有的鎖,導(dǎo)致它們都無法繼續(xù)執(zhí)行。這是一種常見的并發(fā)問題,尤其是在高并發(fā)情況下,事務(wù)在訪問相同的數(shù)據(jù)資源時(shí)容易產(chǎn)生死鎖。

通俗理解:

可以把死鎖類比為兩個(gè)人走在一條窄路上,他們都需要對(duì)方讓路才能繼續(xù)前進(jìn)。A 擋住了 B 的路,B 又擋住了 A 的路,誰(shuí)也不肯退讓,結(jié)果兩個(gè)人都卡住了。這在數(shù)據(jù)庫(kù)中表現(xiàn)為事務(wù) A 等待事務(wù) B 釋放資源,而事務(wù) B 同時(shí)也在等待事務(wù) A 釋放資源,最終兩個(gè)事務(wù)都無法繼續(xù)。

死鎖的產(chǎn)生過程:

  1. 事務(wù) A 獲取資源 X 的鎖 。
  2. 事務(wù) B 獲取資源 Y 的鎖 。
  3. 事務(wù) A 嘗試獲取資源 Y 的鎖,但資源 Y 被事務(wù) B 鎖住,于是事務(wù) A 進(jìn)入等待狀態(tài)。
  4. 事務(wù) B 嘗試獲取資源 X 的鎖,但資源 X 已經(jīng)被事務(wù) A 鎖住,事務(wù) B 也進(jìn)入等待狀態(tài)。
  5. 結(jié)果是:事務(wù) A 等待 B,事務(wù) B 等待 A,形成一個(gè)循環(huán)等待,產(chǎn)生死鎖。

MySQL 中的死鎖機(jī)制:

MySQL 使用的存儲(chǔ)引擎 InnoDB 提供了行級(jí)鎖,這雖然減少了鎖沖突的概率,但也更容易導(dǎo)致死鎖。InnoDB 遇到死鎖時(shí),會(huì)主動(dòng)檢測(cè)并解決這個(gè)問題,通過回滾其中一個(gè)事務(wù)來打破僵局。

死鎖的處理方式:

在 MySQL 中,當(dāng) InnoDB 檢測(cè)到死鎖時(shí),它會(huì)選擇回滾 代價(jià)最小的事務(wù) ,通常是回滾鎖定較少資源的事務(wù)。然后,它會(huì)向客戶端返回一個(gè)錯(cuò)誤消息,類似于:

ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

當(dāng)一個(gè)事務(wù)被回滾后,另一個(gè)事務(wù)可以繼續(xù)執(zhí)行,解決了死鎖問題。

如何避免死鎖?

盡管 MySQL 能自動(dòng)檢測(cè)并處理死鎖,但頻繁出現(xiàn)死鎖會(huì)影響系統(tǒng)性能,因此盡量避免死鎖是很有必要的。以下是一些常見的避免死鎖的方法:

1. 固定鎖的順序

確保所有事務(wù)在訪問多張表或多條記錄時(shí),遵循相同的順序鎖定資源。這樣可以避免不同事務(wù)間出現(xiàn)交叉鎖定,減少死鎖的可能性。

示例:
所有事務(wù)在更新 users 表和 orders 表時(shí),都先鎖住 users 表,再鎖住 orders 表,避免死鎖。

2. 減少鎖定范圍

盡量減少每個(gè)事務(wù)鎖定的范圍和時(shí)間,避免長(zhǎng)時(shí)間占用鎖。例如,盡量縮短事務(wù)的執(zhí)行時(shí)間,減少不必要的查詢。

示例:

BEGIN;
UPDATE users SET age = age + 1 WHERE id = 1;
COMMIT;

盡量避免在一個(gè)事務(wù)內(nèi)進(jìn)行過多的操作或等待用戶輸入。

3. 使用合適的索引

在查詢時(shí)盡量使用索引來減少鎖定的行數(shù),特別是在 UPDATE DELETE 操作時(shí),合適的索引可以減少鎖定的行數(shù),從而降低死鎖的風(fēng)險(xiǎn)。

示例:
user_id 創(chuàng)建索引:

CREATE INDEX idx_user_id ON orders (user_id);

4. 減少并發(fā)量

控制數(shù)據(jù)庫(kù)的并發(fā)訪問量,如果可能的話,避免在高并發(fā)情況下進(jìn)行大批量數(shù)據(jù)操作。高并發(fā)訪問會(huì)增加死鎖的概率。

5. 合理設(shè)置事務(wù)隔離級(jí)別

使用合適的事務(wù)隔離級(jí)別可以減少鎖定沖突。InnoDB 支持多種事務(wù)隔離級(jí)別,最常見的是 REPEATABLE READ READ COMMITTED 。其中, READ COMMITTED 隔離級(jí)別可以減少鎖爭(zhēng)用的情況,從而降低死鎖發(fā)生的概率。

示例:

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

6. 通過批量操作減少鎖定的時(shí)間

如果需要對(duì)大量數(shù)據(jù)進(jìn)行更新或刪除操作,可以考慮分批處理,減少每次事務(wù)鎖定的行數(shù),從而降低死鎖風(fēng)險(xiǎn)。

示例:

DELETE FROM orders WHERE order_date < '2023-01-01' LIMIT 1000;

使用 LIMIT 分批刪除舊數(shù)據(jù)。

如何檢測(cè)死鎖?

當(dāng)死鎖發(fā)生時(shí),InnoDB 會(huì)在錯(cuò)誤日志中記錄下死鎖信息,包含了死鎖的相關(guān)信息以及導(dǎo)致死鎖的事務(wù)和查詢?梢酝ㄟ^以下 SQL 語(yǔ)句獲取死鎖信息:

SHOW ENGINE INNODB STATUS;

這條命令會(huì)顯示 InnoDB 的狀態(tài)信息,其中包含最近一次死鎖的詳細(xì)信息,包括參與死鎖的事務(wù)和鎖的等待情況。

十、你是如何優(yōu)化慢查詢的?

慢查詢的優(yōu)化步驟和方法:

1. 分析慢查詢?nèi)罩?

首先,確保 慢查詢?nèi)罩? (Slow Query Log)已開啟,這是 MySQL 用來記錄執(zhí)行時(shí)間超過指定閾值的查詢。你可以通過分析這些日志,找出系統(tǒng)中耗時(shí)最長(zhǎng)的查詢。

啟用慢查詢?nèi)罩荆?

SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;  -- 設(shè)置慢查詢閾值為 1 秒

之后,你可以查看慢查詢?nèi)罩緛砹私饽男┎樵儓?zhí)行時(shí)間過長(zhǎng),并從這些查詢中入手進(jìn)行優(yōu)化。

2. 使用 EXPLAIN 分析查詢執(zhí)行計(jì)劃

使用 EXPLAIN 命令可以幫助你了解 MySQL 如何執(zhí)行查詢,它會(huì)提供信息如:查詢是否使用了索引、掃描了多少行、排序方式等。你可以通過查看執(zhí)行計(jì)劃,發(fā)現(xiàn)查詢中的性能瓶頸。

示例:

EXPLAIN SELECT * FROM users WHERE name = 'John';

執(zhí)行結(jié)果會(huì)顯示查詢的類型(如 ALL INDEX 、 RANGE 等),表明 MySQL 是否使用了全表掃描( ALL )或者索引( INDEX )。如果看到 ALL 表示全表掃描,這通常是需要優(yōu)化的信號(hào)。

如何解讀一些常見的結(jié)果:

  • type : ALL 表示全表掃描,需要優(yōu)化; range 、 ref const 表示使用了索引,性能較好。
  • rows : 表示 MySQL 預(yù)計(jì)掃描的行數(shù),越少越好。掃描的行數(shù)越多,查詢的開銷越大。
  • key : 顯示 MySQL 使用了哪個(gè)索引,如果顯示為 NULL ,表示沒有使用索引。

3. 創(chuàng)建和優(yōu)化索引

索引是 MySQL 優(yōu)化慢查詢的最常見手段之一。適當(dāng)?shù)乃饕梢燥@著減少查詢的掃描行數(shù),提升查詢速度。

常見的索引優(yōu)化策略:

  • 單列索引 :對(duì)查詢中常用的過濾條件或 WHERE 子句中的字段創(chuàng)建索引。
  • 復(fù)合索引 :對(duì)涉及多個(gè)條件的查詢,創(chuàng)建復(fù)合索引。例如, SELECT * FROM users WHERE age = 30 AND status = 'active'; ,可以為 (age, status) 創(chuàng)建一個(gè)復(fù)合索引。

示例:

CREATE INDEX idx_name ON users (name);
CREATE INDEX idx_age_status ON users (age, status);
  • 覆蓋索引 :如果索引包含查詢所需的所有字段,MySQL 可以直接從索引中讀取數(shù)據(jù),而無需訪問表本身。這樣能減少 I/O 操作,大幅提升查詢效率。

示例:

SELECT name FROM users WHERE age = 30;  -- 如果 name 和 age 都在索引中,MySQL 可以只查索引
  • 避免索引失效 :確保查詢條件能夠正確利用索引。例如:
    • 避免對(duì)索引字段使用函數(shù)或表達(dá)式,如 WHERE UPPER(name) = 'JOHN' 會(huì)導(dǎo)致索引失效。
    • 使用精確匹配,盡量避免 LIKE '%abc' 這種通配符前綴的查詢。

4. 優(yōu)化查詢語(yǔ)句

改進(jìn)查詢語(yǔ)句的寫法可以大幅提升性能。以下是幾種常見的優(yōu)化建議:

  • 選擇合適的數(shù)據(jù)類型 :盡量使用合適的數(shù)據(jù)類型,避免使用過大的字段長(zhǎng)度。比如,用 INT 存儲(chǔ)年齡,而不是用 VARCHAR 。
  • 減少查詢的返回結(jié)果 :避免 SELECT * ,只查詢需要的字段。返回的數(shù)據(jù)越少,查詢速度越快。

示例:

SELECT id, name FROM users WHERE age = 30;  -- 避免 SELECT *,只取所需的字段
  • 分解復(fù)雜查詢 :將復(fù)雜的查詢拆分為多個(gè)小查詢,有時(shí)能提升性能,尤其是在涉及多個(gè)關(guān)聯(lián)表時(shí)。例如,把一個(gè)包含多個(gè) JOIN 的復(fù)雜查詢,拆分成多次查詢緩存中間結(jié)果。

  • 使用 LIMIT 優(yōu)化分頁(yè) :在大表的分頁(yè)查詢中,避免掃描大量數(shù)據(jù)。可以通過主鍵或者索引結(jié)合 LIMIT 優(yōu)化。

示例:

SELECT * FROM users WHERE id > 1000 LIMIT 10;  -- 基于索引的分頁(yè)

5. 優(yōu)化 JOIN 操作

JOIN 操作在多表查詢中常見,但它們?nèi)菀讓?dǎo)致性能問題,特別是當(dāng)表很大時(shí)。優(yōu)化 JOIN 時(shí)的注意事項(xiàng):

  • 確保連接條件字段有索引 :對(duì)于 JOIN 中使用的字段,確保它們有合適的索引。

示例:

SELECT * FROM orders o JOIN users u ON o.user_id = u.id WHERE u.status = 'active';

在這種情況下, user_id id 應(yīng)該分別在 orders users 表上有索引。

  • 盡量減少關(guān)聯(lián)表的數(shù)據(jù)量 :通過先篩選出需要的數(shù)據(jù),再進(jìn)行 JOIN 操作。例如,將篩選條件放在子查詢中,減少需要關(guān)聯(lián)的行數(shù)。

示例:

SELECT * FROM (SELECT id FROM users WHERE status = 'active') u JOIN orders o ON o.user_id = u.id;

6. 調(diào)整 MySQL 配置參數(shù)

MySQL 的一些配置參數(shù)直接影響查詢性能,特別是在高并發(fā)、大數(shù)據(jù)量場(chǎng)景下。以下是一些常見的優(yōu)化參數(shù):

  • innodb_buffer_pool_size :這是 InnoDB 的緩沖池大小,決定了 MySQL 可以用多少內(nèi)存來緩存數(shù)據(jù)頁(yè)。這個(gè)值通常設(shè)置為系統(tǒng)內(nèi)存的 70%-80%,以便盡可能減少磁盤 I/O。

  • query_cache_size :如果系統(tǒng)中大量的查詢結(jié)果是相同的,可以啟用查詢緩存,以減少重復(fù)查詢的開銷。需要注意的是,MySQL 8.0 中查詢緩存被棄用,因?yàn)樗鼘?duì)高并發(fā)場(chǎng)景可能帶來性能瓶頸。

  • tmp_table_size max_heap_table_size :這些參數(shù)決定了臨時(shí)表可以在內(nèi)存中使用的最大大小,增大這些參數(shù)的值,可以避免頻繁將臨時(shí)表寫入磁盤,從而提高排序和 GROUP BY 查詢的效率。

7. 使用分區(qū)表

如果你的表非常大,可以考慮使用 分區(qū)表 來優(yōu)化查詢性能。分區(qū)表將數(shù)據(jù)分成多個(gè)更小的物理子表,MySQL 可以根據(jù)查詢條件直接定位到某個(gè)分區(qū),從而減少掃描的數(shù)據(jù)量。

示例:

CREATE TABLE orders (
    order_id INT,
    order_date DATE,
    user_id INT,
    ...
) PARTITION BY RANGE (YEAR(order_date)) (
    PARTITION p0 VALUES LESS THAN (2010),
    PARTITION p1 VALUES LESS THAN (2015),
    PARTITION p2 VALUES LESS THAN (2020),
    PARTITION p3 VALUES LESS THAN MAXVALUE
);

8. 避免死鎖和長(zhǎng)事務(wù)

如果某個(gè)慢查詢是由于事務(wù)沖突或死鎖造成的,應(yīng)該盡量避免長(zhǎng)事務(wù)或頻繁鎖表。通過控制事務(wù)范圍、使用合適的隔離級(jí)別、避免大批量寫操作等方式,減少鎖等待和死鎖的發(fā)生,從而加快查詢速度。

9. 緩存

除了使用 MySQL 自身的查詢緩存,你還可以使用應(yīng)用層的緩存機(jī)制(如 Redis、Memcached),將頻繁訪問的數(shù)據(jù)緩存到內(nèi)存中,減少數(shù)據(jù)庫(kù)的訪問頻率。

示例:

# 在應(yīng)用層緩存 MySQL 查詢結(jié)果
cache.set('users:active', active_users, timeout=60*5)  # 緩存 5 分鐘

總結(jié):

  • 分析慢查詢?nèi)罩? 和使用 EXPLAIN 了解執(zhí)行計(jì)劃是優(yōu)化慢查詢的第一步。
  • 創(chuàng)建合適的索引 可以顯著提高查詢速度,尤其是在大表中。
  • 優(yōu)化查詢語(yǔ)句和 JOIN 操作 ,盡量減少掃描的行數(shù),并盡量使用索引覆蓋查詢。
  • 通過調(diào)整 MySQL 配置參數(shù) ,提升系統(tǒng)對(duì)內(nèi)存和資源的利用率。
  • 在大表上使用分區(qū)表,并通過緩存減少對(duì)數(shù)據(jù)庫(kù)的壓力

最后說一句(求關(guān)注,求贊,別白嫖我)

最近無意間獲得一份阿里大佬寫的刷題筆記,一下子打通了我的任督二脈,進(jìn)大廠原來沒那么難。
這是大佬寫的, 7701頁(yè)的BAT大佬寫的刷題筆記,讓我offer拿到手軟

本文,已收錄于,我的技術(shù)網(wǎng)站 cxykk.com:程序員編程資料站 ,有大廠完整面經(jīng),工作技術(shù),架構(gòu)師成長(zhǎng)之路,等經(jīng)驗(yàn)分享

求一鍵三連:點(diǎn)贊、分享、收藏

點(diǎn)贊對(duì)我真的非常重要!在線求贊,加個(gè)關(guān)注我會(huì)非常感激!

小編推薦閱讀

好特網(wǎng)發(fā)布此文僅為傳遞信息,不代表好特網(wǎng)認(rèn)同期限觀點(diǎn)或證實(shí)其描述。

相關(guān)視頻攻略

更多

掃二維碼進(jìn)入好特網(wǎng)手機(jī)版本!

掃二維碼進(jìn)入好特網(wǎng)微信公眾號(hào)!

本站所有軟件,都由網(wǎng)友上傳,如有侵犯你的版權(quán),請(qǐng)發(fā)郵件[email protected]

湘ICP備2022002427號(hào)-10 湘公網(wǎng)安備:43070202000427號(hào)© 2013~2024 haote.com 好特網(wǎng)