国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

MySQL 索引優(yōu)化實(shí)踐(單表)

這篇具有很好參考價(jià)值的文章主要介紹了MySQL 索引優(yōu)化實(shí)踐(單表)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

一、前言

??????索引是為了高效查詢(xún)排好序的數(shù)據(jù)結(jié)構(gòu),當(dāng)表數(shù)據(jù)量到達(dá)一個(gè)量級(jí)沒(méi)有對(duì)應(yīng)索引幫助查詢(xún)耗時(shí)會(huì)很長(zhǎng),MySQL資源開(kāi)銷(xiāo)也會(huì)非常大,當(dāng)然索引也不能隨意創(chuàng)建,要做到盡量少的索引解決盡量多的問(wèn)題,這里會(huì)對(duì)一些業(yè)務(wù)場(chǎng)景做索引優(yōu)化演示,這篇文中只介紹單表索引優(yōu)化,如果單表問(wèn)題能解決多表關(guān)聯(lián)查詢(xún)優(yōu)化就簡(jiǎn)單多了。

如果對(duì)MySQL索引原理還有explain SQL分析工具不是很熟悉的可以看看幾篇文章:

  • MySQL 索引底層 B+Tree 原理解析
  • MySQL explain SQL分析工具詳解與最佳實(shí)踐
  • MySQL 索引介紹和最佳實(shí)踐

二、表數(shù)據(jù)準(zhǔn)備

這里要準(zhǔn)備100w數(shù)據(jù)左右的表,表數(shù)據(jù)盡量多一些或者列多一些,如果數(shù)據(jù)太少,測(cè)試的時(shí)候可能看不到效果。

創(chuàng)建訂單信息表

DROP TABLE IF EXISTS `order_info`;
CREATE TABLE `order_info` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '訂單ID',
  `order_no` varchar(100)  NOT NULL COMMENT '訂單編號(hào)',
  `customer_id` bigint(20) NOT NULL COMMENT '客戶(hù)編號(hào)',
  `goods_id` bigint(20) NOT NULL COMMENT '商品ID',
  `goods_title` varchar(100) DEFAULT NULL COMMENT '商品標(biāo)題',
  `order_status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '訂單狀態(tài) 1:待支付 2:已支付 3:已發(fā)貨 4、已收貨',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時(shí)間',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='訂單信息表';

使用存儲(chǔ)過(guò)程插入100w條數(shù)據(jù)

## 創(chuàng)建一個(gè)插入數(shù)據(jù)的存儲(chǔ)過(guò)程
DROP PROCEDURE IF EXISTS insert_procedure;
delimiter;;
CREATE PROCEDURE insert_procedure () 
BEGIN
  DECLARE i INT DEFAULT 1;
  DECLARE goods_id BIGINT DEFAULT CEIL(RAND() * 100);
  DECLARE t_error INTEGER DEFAULT 0;
  DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET t_error=1;
  START TRANSACTION;
  WHILE ( i <= 1000000 ) DO
    INSERT INTO `order_info`(`order_no`,`customer_id`, `goods_id`, `goods_title`, `order_status`, `create_time`) VALUES (CONCAT('ON00000',i), CEIL(RAND() * 100000), goods_id, CONCAT('筆記本電腦',goods_id), MOD(i, 4)+1, NOW());
    SET i = i + 1;
    SET goods_id = CEIL(RAND() * 100);
  END WHILE;
  IF t_error=1 THEN
    ROLLBACK;
  ELSE
    COMMIT;
  END IF;
END;;
delimiter;

# 調(diào)用存儲(chǔ)過(guò)程插入數(shù)據(jù) 我本地插入100w條數(shù)據(jù)耗時(shí)200s
CALL insert_procedure ();

三、常見(jiàn)業(yè)務(wù)無(wú)索引查詢(xún)耗時(shí)測(cè)試

我電腦的配置32G內(nèi)存500G固態(tài),MySQL配置全用默認(rèn),自己測(cè)試先看看自己MySQL配置的innodb_buffer_pool_size設(shè)置的是多少,默認(rèn)是128MB,查看命令SHOW VARIABLES LIKE 'innodb_buffer_pool_size';配置里的單位是字節(jié),InnoDB使用一個(gè)緩沖池來(lái)保存索引和原始數(shù)據(jù),innodb_buffer_pool_size就是控制這個(gè)緩沖池的大小,這個(gè)緩沖池在一些情況下對(duì)查詢(xún)性能影響非常大,線上建議設(shè)置成MySQL能使用內(nèi)存的80%,這里不深入。

3.1、通過(guò)訂單ID / 訂單編號(hào) 查詢(xún)指定訂單

  • 通過(guò)訂單ID查詢(xún)訂單
SELECT * FROM order_info WHERE id = 955;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

  • 通過(guò)訂單編號(hào)查詢(xún)訂單
SELECT * FROM order_info WHERE order_no = 'ON000009999';

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
這里已經(jīng)可以看到查詢(xún)耗時(shí)明顯的差距,我們這里的ID是主鍵,MySQL InnoDB存儲(chǔ)引擎會(huì)自動(dòng)將表中的主鍵設(shè)置為主鍵索引,同時(shí)也是一個(gè)聚簇索引葉子節(jié)點(diǎn)攜帶數(shù)據(jù),而訂單編號(hào)是沒(méi)有索引的會(huì)進(jìn)行全表掃描,會(huì)將ON000009999和這個(gè)表中每行數(shù)據(jù)的訂單編號(hào)都進(jìn)行比對(duì)然后取出滿足條件的數(shù)據(jù)行,100w數(shù)據(jù)查詢(xún)一個(gè)訂單信息耗時(shí)已經(jīng)到了0.6秒左右。

3.2、查詢(xún)訂單列表

查詢(xún)訂單列表一般查詢(xún)條件比較多,如訂單編號(hào)、客戶(hù)編號(hào)、訂單狀態(tài)、創(chuàng)建時(shí)間、創(chuàng)建時(shí)間倒序、是否分頁(yè)做幾個(gè)演示,查詢(xún)條件的內(nèi)容自己看看存儲(chǔ)過(guò)程插入的數(shù)據(jù)長(zhǎng)什么樣。

  • 1、查詢(xún)客戶(hù)編號(hào)為111的訂單列表不分頁(yè),不根據(jù)創(chuàng)建時(shí)間倒序
SELECT * FROM order_info WHERE customer_id = 111 AND create_time >= '2023-10-02 09:57:24' AND create_time <= '2023-10-02 10:00:46';

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

  • 2、查詢(xún)客戶(hù)編號(hào)為111訂單列表分頁(yè),不根據(jù)創(chuàng)建時(shí)間倒序
SELECT * FROM order_info WHERE customer_id = 111 AND create_time >= '2023-10-02 09:57:24' AND create_time <= '2023-10-02 10:00:46' LIMIT 3;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

  • 3、查詢(xún)客戶(hù)編號(hào)為111訂單列表分頁(yè),根據(jù)創(chuàng)建時(shí)間倒序
SELECT * FROM order_info WHERE customer_id = 111 AND create_time >= '2023-10-02 09:57:24' AND create_time <= '2023-10-02 10:00:46' ORDER BY create_time DESC LIMIT 3;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

這里三個(gè)查詢(xún)只有第2個(gè)查詢(xún)相對(duì)較快一點(diǎn),耗時(shí)110毫秒,其它兩個(gè)查詢(xún)耗時(shí)基本上都接近500毫秒,從我們給定的條件來(lái)看區(qū)別就在分頁(yè)或者不分頁(yè),排序或者不排序,一般認(rèn)為分頁(yè)肯定比不分頁(yè)查詢(xún)要快,但是我們看1和2查詢(xún)分頁(yè)比不分頁(yè)耗時(shí)相差接近5倍相差可以說(shuō)是巨大,然后在查詢(xún)3中分頁(yè)但是根據(jù)創(chuàng)建時(shí)間倒序,這里耗時(shí)和查詢(xún)1相近和查詢(xún)2耗時(shí)相差接近5倍,這其中原理挺有趣的會(huì)在下面索引優(yōu)化實(shí)踐中舉例說(shuō)明這一些問(wèn)題。

四、訂單常見(jiàn)業(yè)務(wù)索引優(yōu)化實(shí)踐

這里會(huì)對(duì)一些業(yè)務(wù)場(chǎng)景舉例說(shuō)明,也會(huì)對(duì)索引的一些特性做講解。

4.1、通過(guò)唯一索引和普通索引優(yōu)化通過(guò)訂單編號(hào)查詢(xún)訂單信息

類(lèi)似通過(guò)訂單編號(hào)查詢(xún)訂單信息的業(yè)務(wù)有很多,都是通過(guò)一個(gè)編號(hào)信息如客戶(hù)編號(hào)配送員編號(hào)查詢(xún)一個(gè)一對(duì)一的詳情數(shù)據(jù),這一類(lèi)查詢(xún)都有一個(gè)特性編號(hào)唯一,并且編號(hào)類(lèi)的數(shù)據(jù)大多都是字符串類(lèi)型,這里優(yōu)化可以考慮唯一索引和普通索引,一般我們會(huì)給這一類(lèi)編號(hào)數(shù)據(jù)設(shè)置一個(gè)唯一索引,既保證了數(shù)據(jù)的唯一性也保證了通過(guò)編號(hào)查詢(xún)的性能問(wèn)題。

  • 1、添加唯一索引
ALTER TABLE `order_info` ADD UNIQUE INDEX `idx_orderNo`(`order_no`);
  • 2、添加索引后查詢(xún)
SELECT * FROM order_info WHERE order_no = 'ON000009999';

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
無(wú)索引測(cè)試的時(shí)候耗時(shí)0.538s,添加索引后查詢(xún)性能提升十幾倍,數(shù)據(jù)量越大提升比例越高。

4.2、通過(guò)普通聯(lián)合索引優(yōu)化訂單列表查詢(xún)

??????在上面無(wú)索引查詢(xún)我們列舉了查詢(xún)訂單列表的三個(gè)例子,查詢(xún)耗時(shí)除了第2個(gè)都差不多耗時(shí)0.5s,不算太慢但是對(duì)MySQL性能開(kāi)銷(xiāo)其實(shí)是很大的,如果數(shù)據(jù)量在大一些到500w 1000w,查詢(xún)時(shí)間也會(huì)增加到接受不了數(shù)值,所以必須要優(yōu)化。

4.2.1、分析查詢(xún)字段的查詢(xún)場(chǎng)景

??????優(yōu)化前第一要考慮的就是需要一些什么字段,如我們例子中會(huì)使用訂單編號(hào)、客戶(hù)編號(hào)、訂單狀態(tài)、創(chuàng)建時(shí)間。

分析通過(guò)這四個(gè)字段查詢(xún)的場(chǎng)景:

  • 1、需要根據(jù)訂單編號(hào)查詢(xún)
  • 2、需要根據(jù)客戶(hù)編號(hào)查詢(xún)
  • 3、需要根據(jù)創(chuàng)建時(shí)間查詢(xún)
  • 4、需要根據(jù)訂單狀態(tài)查詢(xún)

這里我給這四個(gè)字段分了四個(gè)查詢(xún)場(chǎng)景,為什么這么分我在下面會(huì)詳細(xì)說(shuō)明。

4.2.2、優(yōu)化各場(chǎng)景查詢(xún)和原因分析

對(duì)于這種列表查詢(xún)使用索引一定要知道索引的一個(gè)特性就是最左前綴原則,索引的匹配一定是從最左邊第一個(gè)字段開(kāi)始匹配的,不能跳過(guò)中間字段匹配,在索引優(yōu)化實(shí)踐中會(huì)詳細(xì)說(shuō)明。

4.2.2.1、需要根據(jù)訂單編號(hào)查詢(xún)

??????在一個(gè)訂單列表如果需要根據(jù)訂單編號(hào)查詢(xún),那么一定是要查詢(xún)一個(gè)唯一的訂單,如果我們有索引那么我們可以通過(guò)一個(gè)訂單編號(hào)快速定位到一條數(shù)據(jù)不用進(jìn)行全表掃描,竟然能快速定位到一條數(shù)據(jù)那么就算還攜帶別的條件那直接回表取出行數(shù)據(jù)再去判斷即可。
??????所以這里只需要?jiǎng)?chuàng)建一個(gè)訂單編號(hào)的索引來(lái)適配所有帶訂單編號(hào)的查詢(xún),我們?cè)诒疚牡?.1的優(yōu)化通過(guò)訂單編號(hào)查詢(xún)訂單信息中創(chuàng)建過(guò)一個(gè)訂單編號(hào)的唯一索引,我們這里就用這個(gè)唯一索引就行。

  • 1、需要根據(jù)訂單編號(hào)查詢(xún)測(cè)試
SELECT * FROM order_info WHERE order_no = 'ON000009999' AND order_status=4;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
執(zhí)行計(jì)劃 EXPLAIN
MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

這里可以看到查詢(xún)耗時(shí)為0.037s,執(zhí)行計(jì)劃中使用到了訂單編號(hào)的索引,掃描估計(jì)行數(shù)為1。

4.2.2.2、需要根據(jù)客戶(hù)編號(hào)查詢(xún)

??????在需要根據(jù)客戶(hù)編號(hào)查詢(xún)的業(yè)務(wù)中一定是以客戶(hù)編號(hào)為主要條件的,還有可能會(huì)攜帶訂單狀態(tài),創(chuàng)建時(shí)間等,一個(gè)客戶(hù)可能會(huì)下很多單,想想自己這些年網(wǎng)購(gòu)和點(diǎn)外面應(yīng)該也有個(gè)100單以上了把,那么這里就不能像訂單編號(hào)只用一個(gè)單字段索引了,我們需要把訂單狀態(tài)和創(chuàng)建時(shí)間也加上,其實(shí)就算不加性能也不會(huì)差太多因?yàn)橐粋€(gè)客戶(hù)訂單本來(lái)也不會(huì)太多,單表幾十條數(shù)據(jù)和幾百條數(shù)據(jù)查詢(xún)差距不會(huì)很大。

  • 1、創(chuàng)建以客戶(hù)編號(hào)起頭的普通聯(lián)合索引
ALTER TABLE `order_info` ADD INDEX `idx_customerId_orderStatus_createTime`(`customer_id`, `order_status`, `create_time`);

我這里會(huì)把訂單狀態(tài)和創(chuàng)建時(shí)間也帶上,某購(gòu)物APP查詢(xún)自己訂單是不是都有狀態(tài)選擇,時(shí)間字段可以用作排序和檢索。

  • 2、需要根據(jù)客戶(hù)編號(hào)查詢(xún)測(cè)試
SELECT * FROM order_info WHERE customer_id = 111 AND order_status=4 AND create_time >= '2023-10-02 09:57:24' AND create_time <= '2023-10-02 10:00:46';

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
執(zhí)行計(jì)劃 EXPLAIN
MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
這里可以看到使用到了我們創(chuàng)建的聯(lián)合索引,并且三個(gè)字段全用到了,客戶(hù)編號(hào)bigint類(lèi)型不能為空占用8字節(jié),訂單狀態(tài)tinyint不能為空占用1字節(jié),創(chuàng)建時(shí)間datetime類(lèi)型占用5個(gè)字節(jié)因?yàn)閯?chuàng)建時(shí)間可為空所以多加一個(gè)字節(jié),創(chuàng)建時(shí)間占用6個(gè)字節(jié),合集15個(gè)字節(jié)和key_len相等。

4.2.2.3、需要根據(jù)創(chuàng)建時(shí)間查詢(xún) 和 需要根據(jù)訂單狀態(tài)查詢(xún)

??????在查詢(xún)訂單列表時(shí)經(jīng)常會(huì)查詢(xún)某個(gè)狀態(tài)某個(gè)時(shí)間有多少訂單,狀態(tài)值只有4個(gè)如果要通過(guò)狀態(tài)值建立索引的話顯然是不可行的,通過(guò)狀態(tài)索引查找某個(gè)類(lèi)型數(shù)據(jù)可能得到的是幾十萬(wàn)行數(shù)據(jù),然后還需要回表獲取聚簇索引數(shù)據(jù),所以對(duì)于這種狀態(tài)值創(chuàng)建單獨(dú)索引時(shí)還需要帶上時(shí)間字段,在單獨(dú)查詢(xún)某個(gè)時(shí)間內(nèi)全部訂單時(shí)也可以使用這個(gè)索引,通過(guò)in查詢(xún)將狀態(tài)值全部包含滿足最左前綴原則就能使用該索引查詢(xún)指定時(shí)間段的全部訂單。

  • 1、添加索引前查詢(xún)某個(gè)時(shí)間段內(nèi)全部訂單
SELECT * FROM order_info WHERE order_status IN (1,2,3,4) AND create_time >= '2023-10-02 09:57:30' AND create_time <= '2023-10-02 09:57:31';

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
因?yàn)槲覀兪桥坎迦氲臅r(shí)間間隔比較相近1秒有好幾千條數(shù)據(jù),自己查詢(xún)測(cè)試的時(shí)候最好控制區(qū)間在2s的樣子。

  • 2、創(chuàng)建訂單狀態(tài)和創(chuàng)建時(shí)間的普通索引
ALTER TABLE `order_info` ADD INDEX `idx_orderStatus_createTime`(`order_status`,`create_time`);
  • 3、查詢(xún)某個(gè)時(shí)間段內(nèi)全部狀態(tài)訂單
SELECT * FROM order_info WHERE order_status IN (1,2,3,4) AND create_time >= '2023-10-02 09:57:30' AND create_time <= '2023-10-02 09:57:40' ;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
執(zhí)行計(jì)劃 EXPLAIN

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
我們這里數(shù)據(jù)是批量插入的,每秒會(huì)插入幾千條數(shù)據(jù),查詢(xún)時(shí)間間隔不能太大了最好在2s的樣子,不然索引可能是會(huì)失效的,要查詢(xún)某個(gè)狀態(tài)的訂單只有把訂單狀態(tài)的的IN查詢(xún)換成=查詢(xún)效果是一樣的,滿足最左前綴原則即可。

五、索引優(yōu)化實(shí)踐

在訂單常見(jiàn)業(yè)務(wù)索引優(yōu)化實(shí)踐中簡(jiǎn)單的介紹了一下在一些場(chǎng)景下創(chuàng)建一些什么索引能提升查詢(xún)效率,但是還有很多可變因素會(huì)影響到索引的使用,也有很多場(chǎng)景可以使用更好的索引,以及索引中很重要的左前綴原則,這里會(huì)對(duì)一些場(chǎng)景做舉例說(shuō)明。

刪除之前創(chuàng)建的索引,創(chuàng)建新的測(cè)試聯(lián)合索引

# 刪除上面創(chuàng)建的三個(gè)索引,避免測(cè)試時(shí)被其它索引干擾,要是沒(méi)有創(chuàng)建則不用刪除
ALTER TABLE `order_info` DROP INDEX `idx_orderNo`;
ALTER TABLE `order_info` DROP INDEX `idx_customerId_orderStatus_createTime`;
ALTER TABLE `order_info` DROP INDEX `idx_orderStatus_createTime`;
# 創(chuàng)建新的測(cè)試聯(lián)合索引
ALTER TABLE `order_info` ADD INDEX `idx_goodsTitle_customerId_orderStatus`(`goods_title`, `customer_id`, `order_status`);

4.1 聯(lián)合索引第一個(gè)字段用范圍查詢(xún)可能不會(huì)走索引

EXPLAIN SELECT * FROM order_info WHERE goods_title > '筆記本電腦9' AND customer_id = 9 AND order_status = 4;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

  • 給一個(gè)區(qū)間值
EXPLAIN SELECT * FROM order_info  WHERE goods_title > '筆記本電腦9' AND goods_title < '筆記本電腦99' AND customer_id = 9 AND order_status = 4;

MySQL5.7
MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

MySQL8.0
MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

聯(lián)合索引第一個(gè)字段就用范圍查找可能不會(huì)走索引,對(duì)于MySQL5.7來(lái)說(shuō)只要第一個(gè)字段用范圍查找不會(huì)走索引,但是對(duì)于MySQL8.0來(lái)說(shuō)給個(gè)查詢(xún)區(qū)間還是可能會(huì)走索引的,前提是區(qū)間也不能太大不然也不會(huì)走索引,MySQL內(nèi)部可能覺(jué)得第一個(gè)字段用范圍,結(jié)果集應(yīng)該很大,回表效率不高,還不如就全表掃描,創(chuàng)建聯(lián)合索引時(shí)千萬(wàn)別把時(shí)間這類(lèi)型字段放第一個(gè)了。

4.2 強(qiáng)制走索引(聯(lián)合索引第一個(gè)字段用范圍查詢(xún)不會(huì)走索引這里強(qiáng)制使用索引)

EXPLAIN SELECT * FROM order_info FORCE INDEX(idx_goodsTitle_customerId_orderStatus) WHERE goods_title > '筆記本電腦9' AND customer_id = 9 AND order_status = 4;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
這里確認(rèn)是使用了我們指定的索引,然后再來(lái)看看查詢(xún)性能怎么樣

  • 不指定強(qiáng)制走索引
    MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

  • 指定強(qiáng)制走索引
    MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

經(jīng)過(guò)對(duì)比發(fā)現(xiàn)強(qiáng)制走索引查詢(xún)時(shí)間能縮短近10倍,所以有時(shí)候MySQL自身并不一定能選擇到性能最高的索引使用方式,需要自己不斷的嘗試對(duì)比出最好的方式。

4.3 使用覆蓋索引優(yōu)化查詢(xún)

EXPLAIN SELECT goods_title,customer_id,order_status FROM order_info WHERE goods_title > '筆記本電腦9' AND customer_id = 9 AND order_status = 4;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
查詢(xún)結(jié)果字段和條件字段都在同一個(gè)索引中,查詢(xún)可以完全使用索引中字段不用回表則稱(chēng)為覆蓋索引,覆蓋索引因?yàn)槟鼙苊饣乇砭退懵?lián)合索引第一個(gè)字段范圍查詢(xún)也能走索引。

4.4 in和or在表數(shù)據(jù)量比較大的情況會(huì)走索引,在表記錄不多的情況下會(huì)選擇全表掃描

  • 100w數(shù)據(jù)表測(cè)試
EXPLAIN SELECT * FROM order_info  WHERE goods_title IN('筆記本電腦8','筆記本電腦9') AND customer_id = 9 AND order_status = 4;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

EXPLAIN SELECT * FROM order_info  WHERE (goods_title = '筆記本電腦8' OR goods_title = '筆記本電腦9') AND customer_id = 9 AND order_status = 4;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

  • 根據(jù)order_info創(chuàng)建一個(gè)只有3條數(shù)據(jù)order_info_copy表進(jìn)行測(cè)試
    MySQL5.7
    MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
    MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
    MySQL8.0
    MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
    MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

這里可以看到MySQL5.7中會(huì)進(jìn)行全表掃描,但是MySQL8.0還是會(huì)走索引,現(xiàn)在MySQL8.0市場(chǎng)上用的已經(jīng)比較多了,它執(zhí)意要走索引肯定有它的道理,而且要通過(guò)索引優(yōu)化查詢(xún)肯定是要測(cè)試比較查詢(xún)效率的,在實(shí)際業(yè)務(wù)中多測(cè)試再看看執(zhí)行計(jì)劃,只要實(shí)踐才知道加的索引是否好用。

4.5 like KK% 一般情況也是可以走索引的

  • like 筆記本電腦999
EXPLAIN SELECT * FROM order_info WHERE goods_title LIKE '筆記本電腦999%' AND customer_id = 9 AND order_status = 4;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

  • like 筆記本電腦9
EXPLAIN SELECT * FROM order_info WHERE goods_title LIKE '筆記本電腦9%' AND customer_id = 9 AND order_status = 4;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

使用like前綴查詢(xún)?cè)诮Y(jié)果集較少的時(shí)候是會(huì)走索引的,如果MySQL認(rèn)為結(jié)果集較大還是不會(huì)走索引,結(jié)合以上幾個(gè)例子可以看出,如果通過(guò)索引查詢(xún)響應(yīng)結(jié)果集過(guò)大并且沒(méi)有滿足覆蓋索引也很有可能不會(huì)走索引,這點(diǎn)MySQL5.7 8.0都是一樣的。

4.6 分頁(yè)查詢(xún)索引使用和優(yōu)化

  • 例1:在沒(méi)有索引且不分頁(yè)的請(qǐng)求下查詢(xún)指定客戶(hù)訂單列表數(shù)據(jù)
EXPLAIN SELECT * FROM order_info WHERE customer_id = 9 ORDER BY goods_title;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

  • 例2:在沒(méi)有索引分頁(yè)查詢(xún)指定客戶(hù)訂單列表數(shù)據(jù)
SELECT * FROM order_info WHERE customer_id = 9 LIMIT 0,3;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

SELECT * FROM order_info WHERE customer_id = 9 LIMIT 80,3;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
通過(guò)這兩個(gè)分頁(yè)查詢(xún)可以看到查詢(xún)從第0條開(kāi)始往后查3條數(shù)據(jù)執(zhí)行耗時(shí)很短,查詢(xún)從第80條開(kāi)始往后查3條數(shù)據(jù)耗時(shí)和不分頁(yè)差不多,因?yàn)镸ySQL分頁(yè)查詢(xún)的時(shí)候會(huì)根據(jù)我們的分頁(yè)條件找出對(duì)應(yīng)結(jié)果集的數(shù)據(jù),比如我們分頁(yè)條件時(shí)customer_id = 9 LIMIT 0,3,MySQL會(huì)先用customer_id = 9去一條條對(duì)比數(shù)據(jù),因?yàn)槲覀兊姆猪?yè)參數(shù)時(shí)0,3也就是說(shuō)找出3條數(shù)據(jù)即可,只要找到了3條數(shù)據(jù)就不會(huì)往后找了,同理LIMIT 80,3的時(shí)候需要找到83條數(shù)據(jù)就不會(huì)往后找了,所以這里我們LIMIT 80,3的時(shí)候和不分頁(yè)耗時(shí)差不了多少,不加分頁(yè)會(huì)掃描全表拿出全表的數(shù)據(jù)。

  • 例3:在沒(méi)有索引分頁(yè)查詢(xún)指定客戶(hù)訂單列表數(shù)據(jù)并且根據(jù)創(chuàng)建時(shí)間排序
SELECT * FROM order_info WHERE customer_id = 9 ORDER BY create_time LIMIT 0,3;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
這里加了一個(gè)排序條件分頁(yè)查詢(xún)后耗時(shí)也和不分頁(yè)差不多,因?yàn)槿绻恿伺判蜃侄问切枰葤呷慝@取全部符合結(jié)果的數(shù)據(jù)才能進(jìn)行分頁(yè)。

  • 例4:創(chuàng)建索引分頁(yè)查詢(xún)指定客戶(hù)訂單列表數(shù)據(jù)并且根據(jù)創(chuàng)建時(shí)間排序(正序)
# 創(chuàng)建索引
ALTER TABLE `order_info` ADD INDEX `idx_customerId_createTime`(`customer_id`, `create_time`);
# 刪除索引
ALTER TABLE `order_info` DROP INDEX `idx_customerId_createTime`;
SELECT * FROM order_info WHERE customer_id = 9 ORDER BY create_time LIMIT 0,3;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
執(zhí)行計(jì)劃 EXPLAIN
MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
創(chuàng)建索引后查詢(xún)快了很多,因?yàn)檫@里是正序的索引默認(rèn)也是正序的根本不用在進(jìn)行排序,下面再試試倒序。

  • 例4:創(chuàng)建索引分頁(yè)查詢(xún)指定客戶(hù)訂單列表數(shù)據(jù)并且根據(jù)創(chuàng)建時(shí)間排序(倒序)
SELECT * FROM order_info WHERE customer_id = 9 ORDER BY create_time DESC LIMIT 0,3;

MySQL 5.7
MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
MySQL8.0
MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
查詢(xún)時(shí)間和正序差不多,但是這里MySQL5.7和MySQL8.0的Extra有點(diǎn)區(qū)別,MySQL8.0可以反向索引掃描,MySQL5.7應(yīng)該是將獲取到的數(shù)據(jù)放入內(nèi)存中排序,也可以創(chuàng)建倒序索引這里不深入。

4.7 order by查詢(xún)索引使用和優(yōu)化

  • 例1:
EXPLAIN SELECT * FROM order_info WHERE goods_title = '筆記本電腦9' AND order_status = 4 ORDER BY customer_id;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

利用最左前綴原則:中間字段不能斷,因此查詢(xún)用到了goods_title索引,從key_len=403也能看出,customer_id索引列用在排序過(guò)程中,因?yàn)镋xtra字段里沒(méi)有using filesort,而且索引本來(lái)就是正序的無(wú)需在排。

  • 列2:
EXPLAIN SELECT * FROM order_info WHERE goods_title = '筆記本電腦9' ORDER BY order_status;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

從explain的執(zhí)行結(jié)果來(lái)看:key_len=403,查詢(xún)使用了goods_title 索引,由于用了order_status進(jìn)行排序,跳過(guò)了
customer_id,出現(xiàn)了Using filesort。

  • 列3:
EXPLAIN SELECT * FROM order_info WHERE goods_title = '筆記本電腦9' ORDER BY customer_id,order_status;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

查找只用到索引goods_title 字段,customer_id和order_status用于排序,無(wú)Using filesort。

  • 列4:
EXPLAIN SELECT * FROM order_info WHERE goods_title = '筆記本電腦9' ORDER BY order_status,customer_id;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

和例3中explain的執(zhí)行結(jié)果一樣,但是出現(xiàn)了Using filesort,因?yàn)樗饕膭?chuàng)建順序?yàn)間oods_title,customer_id,order_status,但是排序的時(shí)候customer_id和order_status顛倒位置了。

  • 列5:
EXPLAIN SELECT * FROM order_info WHERE goods_title = '筆記本電腦9' AND customer_id = 9 ORDER BY order_status,customer_id;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

與例4對(duì)比,在Extra中并未出現(xiàn)Using filesort,因?yàn)閏ustomer_id 為常量,在排序中被優(yōu)化,所以索引未顛倒,不會(huì)出現(xiàn)Using filesort。

  • 列6:
EXPLAIN SELECT * FROM order_info WHERE goods_title = '筆記本電腦9' ORDER BY customer_id ASC,order_status DESC;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

雖然排序的字段列與索引順序一樣,且order by默認(rèn)升序,這里position desc變成了降序,導(dǎo)致與索引的排序方式不同,從而產(chǎn)生Using filesort。

  • 列7:
EXPLAIN SELECT * FROM order_info WHERE goods_title IN ('筆記本電腦9','筆記本電腦10') ORDER BY customer_id,order_status;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
對(duì)于排序來(lái)說(shuō),IN查詢(xún)也是范圍查詢(xún),如果排序查詢(xún)中使用范圍查詢(xún)則索引中只能用到goods_title,后面的字段無(wú)法使用。

  • 列8:
EXPLAIN SELECT * FROM order_info WHERE goods_title > '筆記本電腦9' ORDER BY goods_title;

MySQL5.7
MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

MySQL8.0
MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
MySQL5.7只要是聯(lián)合索引第一個(gè)字段要走范圍查詢(xún),那么索引就沒(méi)法使用,除非覆蓋索引,但是在MySQL8.0時(shí)卻是會(huì)去使用索引的,還可以對(duì)比一下查詢(xún)性能,我這里MySQL5.7全表掃描耗時(shí)1.3s,MySQL8.0走索引耗時(shí)0.8s,兩個(gè)版本MySQL第一次執(zhí)行可能時(shí)間都需要2s的樣子,會(huì)將磁盤(pán)中的聚簇索引葉子節(jié)點(diǎn)數(shù)據(jù)加載到內(nèi)存中,多次執(zhí)行后回表可以直接查內(nèi)存不用再次讀取磁盤(pán)。

4.7 總結(jié)
  • 1、MySQL支持兩種方式的排序filesort和index,Using index是指MySQL掃描索引本身完成排序。index
    效率高,filesort效率低。
  • 2、order by滿足兩種情況會(huì)使用Using index。
    • order by語(yǔ)句使用索引最左前列。
    • 使用where子句與order by子句條件列組合滿足索引最左前列。
  • 3、盡量在索引列上完成排序,遵循索引建立(索引創(chuàng)建的順序)時(shí)的最左前綴法則。
  • 4、如果order by的條件不在索引列上,就會(huì)產(chǎn)生Using filesort。
  • 5、能用覆蓋索引盡量用覆蓋索引
  • 6、group by與order by很類(lèi)似,其實(shí)質(zhì)是先排序后分組,遵照索引創(chuàng)建順序的最左前綴法則。對(duì)于group
    by的優(yōu)化如果不需要排序的可以加上order by null禁止排序。注意,where高于having,能寫(xiě)在where中
    的限定條件就不要去having限定了。

Using filesort文件排序原理詳解

  • filesort文件排序方式
    • 單路排序:是一次性取出滿足條件行的所有字段,然后在sort buffer中進(jìn)行排序;用trace工具可
      以看到sort_mode信息里顯示< sort_key, additional_fields >或者< sort_key,
      packed_additional_fields >
    • 雙路排序(又叫回表排序模式):是首先根據(jù)相應(yīng)的條件取出相應(yīng)的排序字段和可以直接定位行
      數(shù)據(jù)的行 ID,然后在 sort buffer 中進(jìn)行排序,排序完后需要再次取回其它需要的字段;用trace工具
      可以看到sort_mode信息里顯示< sort_key, rowid >
  • MySQL 通過(guò)比較系統(tǒng)變量 max_length_for_sort_data(默認(rèn)1024字節(jié)) 的大小和需要查詢(xún)的字段總大小來(lái)
    判斷使用哪種排序模式。
    • 如果 字段的總長(zhǎng)度小于max_length_for_sort_data ,那么使用 單路排序模式;
    • 如果 字段的總長(zhǎng)度大于max_length_for_sort_data ,那么使用 雙路排序模式。

4.8 count()查詢(xún)優(yōu)化

count查詢(xún)常見(jiàn)有4種寫(xiě)法count(1)、count(字段)、count(主鍵 id)、count(*),這里會(huì)對(duì)4種寫(xiě)法原理和性能做講解,這里MySQL5.7和MySQL8.0區(qū)別有點(diǎn)大,這里分開(kāi)講解,還需要將之前創(chuàng)建的索引全刪除避免測(cè)試被影響。

# 刪除之前創(chuàng)建的所有索引,已經(jīng)刪除的不用重復(fù)執(zhí)行
ALTER TABLE `order_info` DROP INDEX `idx_orderNo`;
ALTER TABLE `order_info` DROP INDEX `idx_customerId_orderStatus_createTime`;
ALTER TABLE `order_info` DROP INDEX `idx_orderStatus_createTime`;
ALTER TABLE `order_info` DROP INDEX `idx_goodsTitle_customerId_orderStatus`;
ALTER TABLE `order_info` DROP INDEX `idx_customerId_createTime`;
4.8.1 MySQL5.7 count()查詢(xún)優(yōu)化

先比對(duì)查詢(xún)時(shí)間后面做總結(jié)

  • MySQL5.7(goods_id字段無(wú)索引)
    MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
    這里我執(zhí)行了很多次得到的執(zhí)行效率結(jié)果都是 count(*) ≈ count(1) > count(id) > count(goods_id)

  • MySQL5.7(goods_id字段建立索引)

# 新增idx_goodsId索引
ALTER TABLE order_info ADD INDEX idx_goodsId(goods_id);
# 刪除idx_goodsId索引
ALTER TABLE `order_info` DROP INDEX `idx_goodsId`;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
這里給goods_id字段建立索引后,我執(zhí)行了很多次得到的執(zhí)行效率結(jié)果也還是 count(*) ≈ count(1) > count(id) > count(goods_id),反而加上索引后count(goods_id)更加慢了,而且有一點(diǎn)蛋疼的事這幾條SQL的執(zhí)行計(jì)劃都是下圖這樣的,理論上應(yīng)該會(huì)展示索引的使用。
MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

  • MySQL5.7 count()查詢(xún)總結(jié)
    • 通過(guò)上面兩個(gè)查詢(xún)效率比對(duì)可以確認(rèn)count(*) ≈ count(1) > count(id) > count(goods_id),在count查詢(xún)的時(shí)候直接使用count(*)或者count(1)是最好的,MySQL使用count(*)并不會(huì)把全部字段取出來(lái),而是專(zhuān)門(mén)做了優(yōu)化,不取值,按行累加,效率很高,count(1)不需要取出字段統(tǒng)計(jì),就用常量1做統(tǒng)計(jì),效率也很高。
    • count(id)可以走主鍵索引,如果有輔助索引會(huì)選擇走輔助索引相對(duì)主鍵索引存儲(chǔ)數(shù)據(jù)更少,檢索性能應(yīng)該更高。
    • 理論上count(goods_id),goods_id沒(méi)有索引時(shí)會(huì)全表掃描拿出goods_id字段統(tǒng)計(jì),建立索引后只用掃描索引統(tǒng)計(jì),效率應(yīng)該更高的,這里測(cè)試好像并沒(méi)有,而且執(zhí)行計(jì)劃中也沒(méi)有顯示其它信息,我這可能是個(gè)例。
    • 我們目的是找到效率最高的查詢(xún)方法,對(duì)于不同業(yè)務(wù)可能需要不同的方式,要找到最合適的方法必須靠實(shí)踐。
4.8.2 MySQL8.0 count()查詢(xún)優(yōu)化
  • MySQL8.0(goods_id字段無(wú)索引)
    MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
    其中count(1)、count(id)、count(*) 都是使用了主鍵索引執(zhí)行計(jì)劃如下
    MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
    count(goods_id)會(huì)進(jìn)行全表掃描
    MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)

  • MySQL8.0(goods_id字段有索引)

# 新增idx_goodsId索引
ALTER TABLE order_info ADD INDEX idx_goodsId(goods_id);
# 刪除idx_goodsId索引
ALTER TABLE `order_info` DROP INDEX `idx_goodsId`;

MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)
添加上索引后四個(gè)查詢(xún)都會(huì)走idx_goodsId索引
MySQL 索引優(yōu)化實(shí)踐(單表),數(shù)據(jù)庫(kù),mysql,數(shù)據(jù)庫(kù)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-729443.html

  • MySQL8.0 count()查詢(xún)總結(jié)
    • 我這里100w數(shù)據(jù)測(cè)試,我執(zhí)行了很多次得到的查詢(xún)效率都差不多,估計(jì)要加大數(shù)據(jù)測(cè)試才能行,不過(guò)和MySQL5.7理論應(yīng)該是一致的count(*) 和 count(1)一定是最穩(wěn)定效率最高的
    • 在count查詢(xún)的時(shí)候直接使用count(*)或者count(1)是最好的,MySQL使用count(*)并不會(huì)把全部字段取出來(lái),而是專(zhuān)門(mén)做了優(yōu)化,不取值,按行累加,效率很高,count(1)不需要取出字段統(tǒng)計(jì),就用常量1做統(tǒng)計(jì),效率也很高。
    • count(id)可以走主鍵索引,如果有輔助索引會(huì)選擇走輔助索引相對(duì)主鍵索引存儲(chǔ)數(shù)據(jù)更少,檢索性能應(yīng)該更高。
    • 理論上count(goods_id),goods_id沒(méi)有索引時(shí)會(huì)全表掃描拿出goods_id字段統(tǒng)計(jì),建立索引后只用掃描索引統(tǒng)計(jì),效率應(yīng)該更高的。

六、索引設(shè)計(jì)原則

  • 1、代碼先行,索引后上
    不知大家一般是怎么給數(shù)據(jù)表建立索引的,是建完表馬上就建立索引嗎?
    這其實(shí)是不對(duì)的,一般應(yīng)該等到主體業(yè)務(wù)功能開(kāi)發(fā)完畢,把涉及到該表相關(guān)sql都要拿出來(lái)分析之后再建立
    索引。
  • 2、聯(lián)合索引盡量覆蓋條件
    比如可以設(shè)計(jì)一個(gè)或者兩三個(gè)聯(lián)合索引(盡量少建單值索引),讓每一個(gè)聯(lián)合索引都盡量去包含sql語(yǔ)句里的
    where、order by、group by的字段,還要確保這些聯(lián)合索引的字段順序盡量滿足sql查詢(xún)的最左前綴原
    則。
  • 3、不要在小基數(shù)字段上建立索引
    索引基數(shù)是指這個(gè)字段在表里總共有多少個(gè)不同的值,比如一張表總共100萬(wàn)行記錄,其中有個(gè)性別字段,
    其值不是男就是女,那么該字段的基數(shù)就是2。
    如果對(duì)這種小基數(shù)字段建立索引的話,還不如全表掃描了,因?yàn)槟愕乃饕龢?shù)里就包含男和女兩種值,根本沒(méi)
    法進(jìn)行快速的二分查找,那用索引就沒(méi)有太大的意義了。
    一般建立索引,盡量使用那些基數(shù)比較大的字段,就是值比較多的字段,那么才能發(fā)揮出B+樹(shù)快速二分查
    找的優(yōu)勢(shì)來(lái)。
  • 4、長(zhǎng)字符串我們可以采用前綴索引
    盡量對(duì)字段類(lèi)型較小的列設(shè)計(jì)索引,比如說(shuō)什么tinyint之類(lèi)的,因?yàn)樽侄晤?lèi)型較小的話,占用磁盤(pán)空間也會(huì)
    比較小,此時(shí)你在搜索的時(shí)候性能也會(huì)比較好一點(diǎn)。
    當(dāng)然,這個(gè)所謂的字段類(lèi)型小一點(diǎn)的列,也不是絕對(duì)的,很多時(shí)候你就是要針對(duì)varchar(255)這種字段建立
    索引,哪怕多占用一些磁盤(pán)空間也是有必要的。
    對(duì)于這種varchar(255)的大字段可能會(huì)比較占用磁盤(pán)空間,可以稍微優(yōu)化下,比如針對(duì)這個(gè)字段的前20個(gè)
    字符建立索引,就是說(shuō),對(duì)這個(gè)字段里的每個(gè)值的前20個(gè)字符放在索引樹(shù)里,類(lèi)似于 KEY
    index(goods_title(20), customer_id, order_status)。
    此時(shí)你在where條件里搜索的時(shí)候,如果是根據(jù)goods_title字段來(lái)搜索,那么此時(shí)就會(huì)先到索引樹(shù)里根據(jù)goods_title
    字段的前20個(gè)字符去搜索,定位到之后前20個(gè)字符的前綴匹配的部分?jǐn)?shù)據(jù)之后,再回到聚簇索引提取出來(lái)
    完整的goods_title字段值進(jìn)行比對(duì)。
    但是假如你要是order by goods_title,那么此時(shí)你的goods_title因?yàn)樵谒饕龢?shù)里僅僅包含了前20個(gè)字符,所以這個(gè)排
    序是沒(méi)法用上索引的, group by也是同理。所以這里大家要對(duì)前綴索引有一個(gè)了解。
  • 5、where與order by沖突時(shí)優(yōu)先where
    在where和order by出現(xiàn)索引設(shè)計(jì)沖突時(shí),到底是針對(duì)where去設(shè)計(jì)索引,還是針對(duì)order by設(shè)計(jì)索引?到
    底是讓where去用上索引,還是讓order by用上索引?
    一般這種時(shí)候往往都是讓where條件去使用索引來(lái)快速篩選出來(lái)一部分指定的數(shù)據(jù),接著再進(jìn)行排序。
    因?yàn)榇蠖鄶?shù)情況基于索引進(jìn)行where篩選往往可以最快速度篩選出你要的少部分?jǐn)?shù)據(jù),然后做排序的成本可
    能會(huì)小很多。
  • 6、基于慢sql查詢(xún)做優(yōu)化
    可以根據(jù)監(jiān)控后臺(tái)的一些慢sql,針對(duì)這些慢sql查詢(xún)做特定的索引優(yōu)化。

到了這里,關(guān)于MySQL 索引優(yōu)化實(shí)踐(單表)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【從刪庫(kù)到跑路】MySQL數(shù)據(jù)庫(kù)的查詢(xún)(單表查詢(xún),多表查詢(xún),內(nèi)外連接,聯(lián)合查詢(xún),子查詢(xún))

    【從刪庫(kù)到跑路】MySQL數(shù)據(jù)庫(kù)的查詢(xún)(單表查詢(xún),多表查詢(xún),內(nèi)外連接,聯(lián)合查詢(xún),子查詢(xún))

    ??專(zhuān)欄【MySQL】 ??喜歡的詩(shī)句:更喜岷山千里雪 三軍過(guò)后盡開(kāi)顏。 ??音樂(lè)分享【如愿】 大一同學(xué)小吉,歡迎并且感謝大家指出我的問(wèn)題?? 在項(xiàng)目開(kāi)發(fā)中,在進(jìn)行數(shù)據(jù)庫(kù)表結(jié)構(gòu)設(shè)計(jì)時(shí),會(huì)根據(jù)業(yè)務(wù)需求以及業(yè)務(wù)模塊之間的關(guān)系,分析并設(shè)計(jì)表結(jié)構(gòu),由于業(yè)務(wù)之間相互關(guān)聯(lián)

    2024年02月10日
    瀏覽(30)
  • MySQL數(shù)據(jù)庫(kù):索引

    MySQL數(shù)據(jù)庫(kù):索引

    ????????索引是一種特殊的文件,包含著對(duì)數(shù)據(jù)表里所有記錄的引用指針??梢詫?duì)表中的一列或多列創(chuàng)建索引,并指定索引的類(lèi)型,各類(lèi)索引有各自的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)。 ? ? ? ? 相當(dāng)于是給數(shù)據(jù)庫(kù)中的數(shù)據(jù)建立了一個(gè)目錄,通過(guò)目錄可以知道數(shù)據(jù)所在位置,然后到指定位置

    2023年04月17日
    瀏覽(93)
  • 【MySql】數(shù)據(jù)庫(kù)索引

    【MySql】數(shù)據(jù)庫(kù)索引

    可以簡(jiǎn)單理解為一本書(shū)的目錄信息,是為了提升查找效率而建立的 1、在創(chuàng)建一個(gè)主鍵、唯一鍵、外鍵時(shí)候,數(shù)據(jù)庫(kù)會(huì)自動(dòng)地針對(duì)查找字段設(shè)置索引; 2、在創(chuàng)建表時(shí)侯,使用 index 進(jìn)行普通索引的聲明 3、修改表結(jié)構(gòu),給指定的字段添加索引 alter table 表名 add index 索引名

    2024年02月03日
    瀏覽(94)
  • MySQL數(shù)據(jù)庫(kù)索引機(jī)制

    MySQL數(shù)據(jù)庫(kù)索引機(jī)制

    MySQL是一款有客戶(hù)端和服務(wù)端的網(wǎng)絡(luò)應(yīng)用,mysql是它的客戶(hù)端,mysqld是它的服務(wù)端。服務(wù)端本質(zhì)就是一個(gè)進(jìn)程,它存在于內(nèi)存當(dāng)中。而我們存儲(chǔ)在MySQL中的數(shù)據(jù)是保存在磁盤(pán)上的,當(dāng)我們對(duì)MySQL中數(shù)據(jù)進(jìn)行增刪查改操作時(shí),不可能是直接在磁盤(pán)上進(jìn)行操作,而是將對(duì)應(yīng)的數(shù)據(jù)加

    2024年02月12日
    瀏覽(100)
  • MySQL數(shù)據(jù)庫(kù)唯一索引

    MySQL數(shù)據(jù)庫(kù)唯一索引

    創(chuàng)建索引是指在某個(gè)表的一列或多列上建立一個(gè)索引,以便提高對(duì)表的訪問(wèn)速度。創(chuàng)建索引有3種方式,分別是1.創(chuàng)建表的時(shí)候創(chuàng)建索引、2.在已經(jīng)存在的表上創(chuàng)建索引和使用3.ALTER TABLE語(yǔ)句來(lái)創(chuàng)建索引。 本文福利, 莬 費(fèi)領(lǐng)取Qt開(kāi)發(fā)學(xué)習(xí)資料包、技術(shù)視頻,內(nèi)容包括(C++語(yǔ)言基

    2024年02月08日
    瀏覽(96)
  • 簡(jiǎn)單認(rèn)識(shí)MySQL數(shù)據(jù)庫(kù)索引

    簡(jiǎn)單認(rèn)識(shí)MySQL數(shù)據(jù)庫(kù)索引

    提示:文章寫(xiě)完后,目錄可以自動(dòng)生成,如何生成可參考右邊的幫助文檔 ●索引是一個(gè)排序的列表,在這個(gè)列表中存儲(chǔ)著索引的值和包含這個(gè)值的數(shù)據(jù)所在行的物理地址(類(lèi)似于C語(yǔ)言的鏈表通過(guò)指針指向數(shù)據(jù)記錄的內(nèi)存地址)。 ●使用索引后可以不用掃描全表來(lái)定位某行的

    2024年02月16日
    瀏覽(31)
  • MySQL數(shù)據(jù)庫(kù)索引的數(shù)據(jù)結(jié)構(gòu)

    數(shù)據(jù)庫(kù)索引的功能就是讓查找更加的高效,所以索引的數(shù)據(jù)結(jié)構(gòu)應(yīng)該是能夠加速查找的數(shù)據(jù)結(jié)構(gòu)。 MySQL的innoDB存儲(chǔ)引擎的索引的數(shù)據(jù)結(jié)構(gòu)就是多叉搜索樹(shù)中的b+樹(shù),這可以說(shuō)是為索引量身定做的一個(gè)數(shù)據(jù)結(jié)構(gòu)。 首先,索引可以通過(guò)主鍵,unique修飾創(chuàng)建,也可以直接使用sql語(yǔ)句

    2024年02月10日
    瀏覽(31)
  • 【MySql系列】深入解析數(shù)據(jù)庫(kù)索引

    【MySql系列】深入解析數(shù)據(jù)庫(kù)索引

    MySQL索引是數(shù)據(jù)庫(kù)中一個(gè)關(guān)鍵的概念,它可以極大地提高查詢(xún)性能,加快數(shù)據(jù)檢索速度。但是,要充分發(fā)揮索引的作用,需要深入理解它們的工作原理和使用方式。 在本文中,我們將深入解析MySQL索引,探討它們的重要性、類(lèi)型、創(chuàng)建、維護(hù)以及最佳實(shí)踐。 在數(shù)據(jù)庫(kù)中,索引

    2024年02月08日
    瀏覽(32)
  • 【MySQL數(shù)據(jù)庫(kù) | 第十七篇】索引以及索引結(jié)構(gòu)介紹

    【MySQL數(shù)據(jù)庫(kù) | 第十七篇】索引以及索引結(jié)構(gòu)介紹

    目錄 前言: 索引簡(jiǎn)介:? 索引結(jié)構(gòu): ? ? ? ? ??二叉樹(shù)索引結(jié)構(gòu) ? ? ? ??Tree(普通二叉樹(shù)) ? ? ? ??B-Tree(多路平衡查找樹(shù)) ? ? ? ??B+Tree ? ? ? ???哈希索引數(shù)據(jù)結(jié)構(gòu) 總結(jié): 在實(shí)際生活中,我們對(duì)SQL語(yǔ)句進(jìn)行優(yōu)化實(shí)際上有很大一部分都是對(duì)索引進(jìn)行優(yōu)化,因此對(duì)索引

    2024年02月09日
    瀏覽(40)
  • MySQL數(shù)據(jù)庫(kù)索引的種類(lèi)、創(chuàng)建、刪除

    MySQL數(shù)據(jù)庫(kù)索引的種類(lèi)、創(chuàng)建、刪除

    目錄 一:MySQL 索引 1、MySQL 索引介紹 2、?索引的作用 ?3、索引的副作用 4、?創(chuàng)建索引的原則依據(jù) ?二、索引的分類(lèi)和創(chuàng)建 1、?普通索引 (1)?直接創(chuàng)建索引 (2)?修改表方式創(chuàng)建 (3)?創(chuàng)建表的時(shí)候指定索引 2、?唯一索引 (1)?直接創(chuàng)建唯一索引 (2)?修改表方式創(chuàng)建

    2024年02月09日
    瀏覽(1049)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包