最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

21個MySQL索引優(yōu)化實戰(zhàn)技巧分享

 更新時間:2025年05月23日 08:42:22   作者:風(fēng)象南  
MySQL索引優(yōu)化是提升數(shù)據(jù)庫性能的關(guān)鍵手段,一個合理的索引設(shè)計和使用策略,往往能將查詢速度提升幾十倍甚至上百倍,本文總結(jié)了21個MySQL索引優(yōu)化的實戰(zhàn)技巧,有需要的可以了解下

MySQL索引優(yōu)化是提升數(shù)據(jù)庫性能的關(guān)鍵手段,一個合理的索引設(shè)計和使用策略,往往能將查詢速度提升幾十倍甚至上百倍。

然而,索引優(yōu)化并不簡單,既需要扎實的理論基礎(chǔ),也需要豐富的實戰(zhàn)經(jīng)驗。

本文總結(jié)了21個MySQL索引優(yōu)化的實戰(zhàn)技巧,從索引選擇、設(shè)計到維護(hù)、監(jiān)控的全生命周期,幫助你解決日常開發(fā)中的索引性能問題。

基礎(chǔ)知識回顧

在具體介紹前,讓我們先簡單回顧索引的基礎(chǔ)知識:

MySQL常用的索引類型包括:主鍵索引、唯一索引、普通索引、聯(lián)合索引、全文索引等。

其中最常用的B+樹索引,具有以下特點:

  • 非葉子節(jié)點只存儲鍵值信息
  • 所有葉子節(jié)點包含了完整的數(shù)據(jù)記錄
  • 葉子節(jié)點通過指針連接,方便范圍查詢
  • 所有節(jié)點按鍵值大小排序

理解這些基礎(chǔ)對于后續(xù)優(yōu)化至關(guān)重要。接下來,讓我們進(jìn)入正題。

一、索引設(shè)計優(yōu)化

1. 遵循最左匹配原則,合理設(shè)計聯(lián)合索引順序

聯(lián)合索引的順序直接影響其使用效率。MySQL會從左到右依次使用索引列,如果中間某列沒有使用,則后面的列也無法使用索引。

錯誤示例:

-- 創(chuàng)建索引(name, age, city)
CREATE INDEX idx_user_name_age_city ON user(name, age, city);

-- 以下查詢無法充分利用索引
SELECT * FROM user WHERE age = 25 AND city = 'Beijing';  -- name列缺失,只能全表掃描
SELECT * FROM user WHERE name = 'Tom' AND city = 'Beijing';  -- 中間age列缺失,city無法使用索引

優(yōu)化方法:

1. 將選擇性高的列放在前面(選擇性 = 不重復(fù)值 / 總記錄數(shù))

2. 將常用于條件查詢的列放在前面

3. 考慮范圍查詢的列放在最后

-- 假設(shè)選擇性:city < name < age
CREATE INDEX idx_user_name_age_city ON user(name, age, city);

-- 充分利用索引的查詢
SELECT * FROM user WHERE name = 'Tom' AND age = 25;
SELECT * FROM user WHERE name = 'Tom' AND age = 25 AND city = 'Beijing';

2. 利用覆蓋索引避免回表查詢

回表操作是指通過索引找到對應(yīng)的行記錄指針,再通過指針去查詢完整記錄的過程。

如果查詢只需要返回索引包含的列,則可以避免回表,這稱為覆蓋索引。

優(yōu)化前:

-- 創(chuàng)建普通索引
CREATE INDEX idx_user_name ON user(name);

-- 需要回表查詢
SELECT id, name, age, city FROM user WHERE name = 'Tom';

優(yōu)化后:

-- 創(chuàng)建包含所需字段的索引
CREATE INDEX idx_user_name_age_city ON user(name, age, city);

-- 使用覆蓋索引,無需回表
SELECT name, age, city FROM user WHERE name = 'Tom';

3. 針對字符串列使用前綴索引

對于CHAR和VARCHAR類型的列,如果整列長度較大,可以只索引開頭的部分字符,這樣可以大幅減少索引占用空間,提高索引效率。

優(yōu)化方法:

-- 假設(shè)product_desc是較長的產(chǎn)品描述文本
CREATE INDEX idx_product_desc ON product(product_desc(50));

如何確定前綴長度?可以通過計算選擇性來確定:

-- 計算不同前綴長度的選擇性
SELECT 
    COUNT(DISTINCT LEFT(product_desc, 10)) / COUNT(*) AS sel_10,
    COUNT(DISTINCT LEFT(product_desc, 20)) / COUNT(*) AS sel_20,
    COUNT(DISTINCT LEFT(product_desc, 30)) / COUNT(*) AS sel_30,
    COUNT(DISTINCT LEFT(product_desc, 40)) / COUNT(*) AS sel_40,
    COUNT(DISTINCT LEFT(product_desc, 50)) / COUNT(*) AS sel_50,
    COUNT(DISTINCT product_desc) / COUNT(*) AS sel_full
FROM product;

選擇一個接近完整列選擇性的前綴長度即可。

注意事項: 使用前綴索引后,無法使用該索引做ORDER BY或GROUP BY,也無法使用覆蓋索引。

4. 合理使用復(fù)合索引替代多個單列索引

多個單列索引在多條件查詢時,MySQL只會選擇一個索引。而復(fù)合索引可以同時滿足多個條件的查詢需求。

優(yōu)化前:

-- 單獨創(chuàng)建兩個索引
CREATE INDEX idx_user_age ON user(age);
CREATE INDEX idx_user_city ON user(city);

-- MySQL通常只會選擇一個索引
SELECT * FROM user WHERE age = 25 AND city = 'Beijing';

優(yōu)化后:

-- 創(chuàng)建一個復(fù)合索引
CREATE INDEX idx_user_age_city ON user(age, city);

-- 可以同時使用age和city條件
SELECT * FROM user WHERE age = 25 AND city = 'Beijing';

5. 使用前綴索引優(yōu)化模糊查詢的左匹配

LIKE語句使用通配符前綴(如'%abc')會導(dǎo)致索引失效。但對于右匹配模式(如'abc%'),索引仍然有效。

可以使用索引的查詢:

-- 可以使用索引
SELECT * FROM products WHERE product_name LIKE 'iphone%';

無法使用索引的查詢:

-- 無法使用索引
SELECT * FROM products WHERE product_name LIKE '%iphone%';

優(yōu)化方法:對于需要搜索包含某個關(guān)鍵詞的記錄,可以考慮全文索引或搜索引擎。對于簡單場景,也可以通過字段冗余解決:

-- 添加一個反轉(zhuǎn)字段
ALTER TABLE products ADD product_name_reversed VARCHAR(255);

-- 觸發(fā)器維護(hù)反轉(zhuǎn)值, 此處為了簡單表示整體實現(xiàn)思路, 實際通常在代碼中進(jìn)行反轉(zhuǎn)值賦值
DELIMITER //
CREATE TRIGGER product_insert BEFORE INSERT ON products
FOR EACH ROW
BEGIN
    SET NEW.product_name_reversed = REVERSE(NEW.product_name);
END; //
DELIMITER ;

-- 創(chuàng)建反轉(zhuǎn)字段的索引
CREATE INDEX idx_product_name_rev ON products(product_name_reversed);

-- 搜索以'phone'結(jié)尾的產(chǎn)品
SELECT * FROM products 
WHERE product_name_reversed LIKE CONCAT(REVERSE('phone'), '%');

二、索引使用優(yōu)化

6. 避免在WHERE子句中對字段進(jìn)行函數(shù)運算

在字段上使用函數(shù)會導(dǎo)致索引失效,應(yīng)該把運算轉(zhuǎn)移到值上。

錯誤用法:

-- 索引失效
SELECT * FROM orders WHERE YEAR(create_time) = 2023;

優(yōu)化方法:

-- 可以使用索引
SELECT * FROM orders 
WHERE create_time >= '2023-01-01' AND create_time < '2024-01-01';

7. 避免隱式類型轉(zhuǎn)換導(dǎo)致索引失效

MySQL在進(jìn)行查詢時,如果字段類型與條件值類型不匹配,會進(jìn)行隱式類型轉(zhuǎn)換,可能導(dǎo)致索引失效。

錯誤用法:

-- user_id是varchar類型,但使用了整數(shù)條件
CREATE INDEX idx_user_id ON users(user_id);
SELECT * FROM users WHERE user_id = 12345;  -- 索引可能失效

優(yōu)化方法:

-- 確保條件值類型與字段類型一致
SELECT * FROM users WHERE user_id = '12345';  -- 使用字符串類型

8. 小心使用NOT、!=、<>、!<、!>、NOT IN、NOT LIKE等否定操作符

否定條件通常會導(dǎo)致索引失效,因為數(shù)據(jù)庫需要檢查所有不滿足條件的記錄。

優(yōu)化方法:盡量用肯定表達(dá)式替代否定表達(dá)式:

-- 優(yōu)化前:無法充分利用索引
SELECT * FROM products WHERE category_id != 5;

-- 優(yōu)化后:可以使用索引
SELECT * FROM products WHERE category_id < 5 OR category_id > 5;

9. 合理使用LIMIT優(yōu)化分頁查詢

大偏移量的LIMIT分頁查詢效率較低,因為MySQL需要檢索前N條記錄然后丟棄。

優(yōu)化前:

-- 性能較差的分頁查詢
SELECT * FROM products ORDER BY id LIMIT 100000, 10;

優(yōu)化方法1 - 使用索引覆蓋掃描:

-- 先獲取ID,再關(guān)聯(lián)查詢完整數(shù)據(jù)
SELECT p.* FROM products p
JOIN (
    SELECT id FROM products ORDER BY id LIMIT 100000, 10
) tmp ON p.id = tmp.id;

優(yōu)化方法2 - 使用上次查詢的最大ID:

-- 假設(shè)已知上一頁的最大ID是100233
SELECT * FROM products WHERE id > 100233 ORDER BY id LIMIT 10;

10. 避免使用SELECT *,只查詢需要的列

使用SELECT *會返回所有列,可能破壞覆蓋索引的效果,并增加網(wǎng)絡(luò)和內(nèi)存開銷。

優(yōu)化前:

-- 可能導(dǎo)致不必要的開銷
SELECT * FROM users WHERE name = 'Tom';

優(yōu)化后:

-- 只返回需要的列,可能利用覆蓋索引
SELECT id, name, email FROM users WHERE name = 'Tom';

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

在優(yōu)化前,先使用EXPLAIN分析SQL語句的執(zhí)行計劃,了解索引使用情況。

EXPLAIN SELECT * FROM users WHERE name = 'Tom' AND age > 20;

重點關(guān)注以下字段:

  • type: 從好到差依次是:system > const > eq_ref > ref > range > index > ALL
  • key: 實際使用的索引
  • rows: 預(yù)計需要掃描的行數(shù)
  • Extra: 額外信息,如"Using index"表示使用了覆蓋索引

三、特殊場景索引優(yōu)化

12. 使用索引排序優(yōu)化ORDER BY操作

如果ORDER BY的列與WHERE使用的列不一致,排序無法使用索引,會導(dǎo)致文件排序。

優(yōu)化前:

-- WHERE和ORDER BY使用不同的列,可能導(dǎo)致文件排序
CREATE INDEX idx_user_name ON users(name);
SELECT * FROM users WHERE name = 'Tom' ORDER BY age;

優(yōu)化后:

-- 創(chuàng)建聯(lián)合索引同時包含WHERE和ORDER BY的列
CREATE INDEX idx_user_name_age ON users(name, age);
SELECT * FROM users WHERE name = 'Tom' ORDER BY age;

注意事項: ORDER BY的多個字段需要與索引順序一致,且排序方向需一致(全ASC或全DESC)。

13. 在大表上創(chuàng)建索引的最佳實踐

在大表上直接創(chuàng)建索引可能會導(dǎo)致長時間鎖表??梢允褂靡韵路椒▋?yōu)化:

方法1 - 使用低峰期操

-- 在低峰期執(zhí)行索引創(chuàng)建
CREATE INDEX idx_order_status ON orders(status);

方法2 - 使用在線DDL(MySQL 8.0+):

-- 使用ALGORITHM和LOCK選項
CREATE INDEX idx_order_status ON orders(status)
ALGORITHM=INPLACE, LOCK=NONE;

方法3 - 使用pt-online-schema-change工具:

pt-online-schema-change --alter "ADD INDEX idx_order_status (status)" \
--host=localhost --user=root --ask-pass --database=mydb --table=orders \
--execute

14. 使用虛擬列為計算結(jié)果創(chuàng)建索引

對于經(jīng)常需要計算后過濾的場景,可以使用虛擬列并在其上創(chuàng)建索引。

-- 添加虛擬列存儲計算結(jié)果
ALTER TABLE products 
ADD total_value DECIMAL(10,2) AS (price * quantity) VIRTUAL;

-- 在虛擬列上創(chuàng)建索引
CREATE INDEX idx_total_value ON products(total_value);

-- 使用計算列進(jìn)行查詢
SELECT * FROM products WHERE total_value > 10000;

15. 使用哈希索引優(yōu)化等值查詢

InnoDB不支持顯式的哈希索引,但我們可以自己實現(xiàn):

-- 添加哈希列
ALTER TABLE users ADD name_hash INT UNSIGNED 
GENERATED ALWAYS AS (crc32(name)) STORED;

-- 在哈希列上創(chuàng)建索引
CREATE INDEX idx_name_hash ON users(name_hash);

-- 使用哈希索引查詢
SELECT * FROM users 
WHERE name_hash = crc32('Tom') AND name = 'Tom';

注意最后還需要驗證原始值,因為哈??赡軟_突。

四、索引維護(hù)優(yōu)化

16. 定期優(yōu)化和重建索引

隨著數(shù)據(jù)變化,索引可能變得碎片化,影響性能。定期優(yōu)化表和重建索引可以改善性能。

-- 分析表
ANALYZE TABLE orders;

-- 優(yōu)化表
OPTIMIZE TABLE orders;

-- 或者重建索引
ALTER TABLE orders DROP INDEX idx_status, ADD INDEX idx_status(status);

建議: 設(shè)置一個低峰期的定時任務(wù),對重要表執(zhí)行優(yōu)化操作。

17. 控制單表上的索引數(shù)量

索引數(shù)量過多會影響寫性能,建議每個表的索引數(shù)量控制在5個以內(nèi)。

優(yōu)化方法:

1. 刪除重復(fù)和未使用的索引

2. 合并功能類似的索引

-- 查找未使用的索引
SELECT * FROM schema_unused_indexes;  -- Performance Schema

-- 查找重復(fù)的索引
SELECT * FROM sys.schema_redundant_indexes;  -- Sys Schema

18. 使用降序索引優(yōu)化排序

MySQL 8.0+支持降序索引,可以優(yōu)化混合排序方向的查詢。

-- 創(chuàng)建混合排序方向的索引(MySQL 8.0+)
CREATE INDEX idx_user_age_score ON users(age ASC, score DESC);

-- 可以高效執(zhí)行的查詢
SELECT * FROM users ORDER BY age ASC, score DESC;

19. 使用部分索引優(yōu)化高選擇性數(shù)據(jù)

MySQL 8.0+支持在WHERE條件滿足時才為行創(chuàng)建索引記錄,減少索引大小。

-- 只為活躍用戶創(chuàng)建索引(MySQL 8.0+)
CREATE INDEX idx_active_users ON users(name, email) 
WHERE status = 'active';

五、索引監(jiān)控與進(jìn)階技巧

20. 利用索引統(tǒng)計信息進(jìn)行調(diào)優(yōu)

MySQL維護(hù)了索引統(tǒng)計信息,可以幫助優(yōu)化器選擇合適的索引。有時統(tǒng)計信息不準(zhǔn)確會導(dǎo)致次優(yōu)的執(zhí)行計劃。

-- 查看表的統(tǒng)計信息
SHOW TABLE STATUS LIKE 'users';

-- 查看索引的基數(shù)
SHOW INDEX FROM users;

-- 刷新統(tǒng)計信息
ANALYZE TABLE users;

21. 使用索引提示(Index Hints)解決優(yōu)化器選擇問題

有時MySQL優(yōu)化器的選擇不是最優(yōu)的,可以使用索引提示強(qiáng)制使用特定索引。

-- 強(qiáng)制使用特定索引
SELECT * FROM users FORCE INDEX(idx_name_age) 
WHERE name = 'Tom' AND age > 20;

-- 忽略特定索引
SELECT * FROM users IGNORE INDEX(idx_status) 
WHERE status = 'active' AND age > 20;

建議: 索引提示應(yīng)該是最后的手段,通常先嘗試優(yōu)化表結(jié)構(gòu)和索引設(shè)計。

總結(jié)

索引優(yōu)化是一個持續(xù)的過程,需要結(jié)合業(yè)務(wù)特點、數(shù)據(jù)分布和查詢模式來綜合考慮。

優(yōu)秀的索引設(shè)計需要理論知識和實踐經(jīng)驗的結(jié)合。

以上就是21個MySQL索引優(yōu)化實戰(zhàn)技巧分享的詳細(xì)內(nèi)容,更多關(guān)于MySQL索引的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Mysql中的圖形化界面方式

    Mysql中的圖形化界面方式

    推薦使用MySQL Workbench作為官方免費工具,配置遠(yuǎn)程連接需指定端口以確保安全,通過命令查看端口號并測試連接設(shè)置
    2025-08-08
  • MySQL中l(wèi)ength()、char_length()的區(qū)別

    MySQL中l(wèi)ength()、char_length()的區(qū)別

    在MySQL中l(wèi)ength(str)、char_length(str)都屬于判斷長度的內(nèi)置函數(shù),本文主要介紹了MySQL中l(wèi)ength()、char_length()的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • 論一條select語句在MySQL是怎樣執(zhí)行的

    論一條select語句在MySQL是怎樣執(zhí)行的

    本文將建立一套建立一套MySQL的知識框架,通過討論select語句在MySQL是怎樣執(zhí)行的來展開內(nèi)容,感興趣的小伙伴一起來看下文吧
    2021-08-08
  • 關(guān)于mysql數(shù)據(jù)庫誤刪除后的數(shù)據(jù)恢復(fù)操作說明

    關(guān)于mysql數(shù)據(jù)庫誤刪除后的數(shù)據(jù)恢復(fù)操作說明

    下面小編就為大家?guī)硪黄P(guān)于mysql數(shù)據(jù)庫誤刪除后的數(shù)據(jù)恢復(fù)操作說明。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • mysql 5.7.21 解壓版安裝配置方法圖文教程

    mysql 5.7.21 解壓版安裝配置方法圖文教程

    這篇文章主要為大家詳細(xì)介紹了mysql 5.7.21 解壓版安裝配置方法圖文教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • mysql 帶多個條件的查詢方式

    mysql 帶多個條件的查詢方式

    這篇文章主要介紹了mysql 帶多個條件的查詢方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • windows7下啟動mysql服務(wù)出現(xiàn)服務(wù)名無效的原因及解決方法

    windows7下啟動mysql服務(wù)出現(xiàn)服務(wù)名無效的原因及解決方法

    這篇文章主要介紹了windows7下啟動mysql服務(wù)出現(xiàn)服務(wù)名無效的原因及解決方法,需要的朋友可以參考下
    2014-06-06
  • MySQL索引使用說明(單列索引和多列索引)

    MySQL索引使用說明(單列索引和多列索引)

    這篇文章主要討論MySQL選擇索引時單列單列索引和多列索引使用,以及多列索引的最左前綴原則,需要的朋友可以參考下
    2018-01-01
  • mysql 5.7 zip 文件在 windows下的安裝教程詳解

    mysql 5.7 zip 文件在 windows下的安裝教程詳解

    這篇文章主要介紹了mysql 5.7 zip 文件在 windows下的安裝步驟,首先我們需要先下載mysql最新版本然后解壓文件夾,本文介紹的非常詳細(xì),具有參考借鑒價值,需要的朋友可以參考下
    2016-09-09
  • MySQL中DATE_FORMAT時間函數(shù)的使用小結(jié)

    MySQL中DATE_FORMAT時間函數(shù)的使用小結(jié)

    本文主要介紹了MySQL中DATE_FORMAT時間函數(shù)的使用小結(jié),用于格式化日期/時間字段,可提取年月、統(tǒng)計月份數(shù)據(jù)、精確到天,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-08-08

最新評論

高唐县| 改则县| 高青县| 枣庄市| 炉霍县| 石楼县| 贞丰县| 常山县| 大姚县| 光泽县| 天全县| 左云县| 东莞市| 鄂托克前旗| 黄陵县| 东台市| 道孚县| 凤翔县| 普兰店市| 瑞丽市| 苗栗市| 都昌县| 南雄市| 安吉县| 上饶市| 平塘县| 拉萨市| 德清县| 全南县| 湖口县| 响水县| 呼和浩特市| 张家口市| 政和县| 海城市| 乌兰察布市| 永城市| 茶陵县| 临泽县| 贵定县| 浦县|