您好,登錄后才能下訂單哦!
這篇文章主要講解了“怎么合理的使用MySQL索引結(jié)構(gòu)和查詢”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“怎么合理的使用MySQL索引結(jié)構(gòu)和查詢”吧!
在MySQL使用的過程中,所謂的性能問題,在大部分的場(chǎng)景下都是指查詢的性能,導(dǎo)致查詢緩慢的根本原因是數(shù)據(jù)量的不斷變大,解決查詢性能的最常見手段是:針對(duì)查詢的業(yè)務(wù)場(chǎng)景,設(shè)計(jì)合理的索引結(jié)構(gòu)。
索引的使用并不是越多越好,而是針對(duì)業(yè)務(wù)下的查詢場(chǎng)景,不斷的改進(jìn)和優(yōu)化,例如電商系統(tǒng)中用戶訂單的場(chǎng)景,假設(shè)存在如下表結(jié)構(gòu):
CREATE TABLE `ds_user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵id', `user_name` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用戶表'; CREATE TABLE `ds_order` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵id', `user_id` int(11) NOT NULL COMMENT '用戶ID', `order_no` varchar(60) NOT NULL COMMENT '訂單號(hào)', `product_name` varchar(50) DEFAULT NULL COMMENT '產(chǎn)品名稱', `number` int(11) DEFAULT '1' COMMENT '個(gè)數(shù)', `unit_price` decimal(10,2) DEFAULT '0.00' COMMENT '單價(jià)', `total_price` decimal(10,2) DEFAULT '0.00' COMMENT '總價(jià)', `order_state` int(2) DEFAULT '1' COMMENT '1待支付,2已支付,3已發(fā)貨,4已簽收', `order_remark` varchar(50) DEFAULT NULL COMMENT '訂單備注', `create_time` datetime DEFAULT NULL COMMENT '創(chuàng)建時(shí)間', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='訂單表';
用戶和訂單的管理表,在電商的業(yè)務(wù)中很常見,可以通過對(duì)該業(yè)務(wù)分析,看看常用的索引結(jié)構(gòu):
用戶方:
基于用戶的查詢,多數(shù)是基于用戶ID(user_id);
基于訂單號(hào)(order_no),查看物流的信息;
運(yùn)營方:
基于時(shí)間段的流水明細(xì)(create_time)或排序;
基于訂單狀態(tài)的篩選(order_state)和統(tǒng)計(jì);
基于產(chǎn)品(product_name)的數(shù)據(jù)統(tǒng)計(jì)分析;
這樣一個(gè)流程分析走下來,即可以在開發(fā)初期,確定哪些結(jié)構(gòu)是查詢必須用到的,預(yù)先做好索引結(jié)構(gòu),避免數(shù)據(jù)量龐大到影響性能時(shí)再去考慮使用索引。
有些時(shí)候會(huì)考慮放棄一些查詢條件,例如基于產(chǎn)品名稱的數(shù)據(jù)統(tǒng)計(jì),走定時(shí)任務(wù)的方式,用來緩解表的查詢壓力,處理的方式是多樣的。
優(yōu)秀的索引設(shè)計(jì),都是建立在對(duì)業(yè)務(wù)數(shù)據(jù)的理解上,考慮業(yè)務(wù)數(shù)據(jù)的查詢方式,提高查詢效率。
單列索引,即索引建立在表的一個(gè)字段上,一個(gè)表可以有多個(gè)單列索引,使用起來相對(duì)比較簡(jiǎn)單:
CREATE INDEX user_id_index ON ds_order(user_id) USING BTREE;
主鍵索引,或者上述的user_id_index都是單列索引。
業(yè)務(wù)場(chǎng)景:基于用戶自己對(duì)訂單查詢,和管理系統(tǒng),訂單和用戶的關(guān)聯(lián)查詢,所以訂單表的user_id需要一個(gè)索引。
組合索引包含兩個(gè)或兩個(gè)以上的列,組合索引相比單列索引復(fù)雜很多,如何建立組合索引,和業(yè)務(wù)關(guān)聯(lián)度非常高,在使用組合索引時(shí),還需要考慮查詢條件的順序。
CREATE INDEX state_create_time_index ON `ds_order`(`create_time`,`order_state`);
如上就是組合索引,實(shí)際包含的是2個(gè)索引 (create_time) (create_time,order_state),這樣查詢就涉及到最左前綴的原則,必須按照順序來查詢,這里下面詳說。
業(yè)務(wù)場(chǎng)景:首先單說這里組合索引,在業(yè)務(wù)開發(fā)中,常見訂單狀態(tài)的統(tǒng)計(jì),基于統(tǒng)計(jì)結(jié)果做運(yùn)營分析,另外就是在運(yùn)營系統(tǒng)中,基于創(chuàng)建時(shí)間段的篩選條件是默認(rèn)存在的,避免全部數(shù)據(jù)實(shí)時(shí)掃描;一些其他的常見查詢也都是條件加時(shí)間段的查詢模式。
如果需要加索引的列是很長的字符串,那么索引會(huì)變的龐大臃腫,起到的效果可能并不是很明顯。這時(shí)候可以截取列的前面一部分,創(chuàng)建索引,節(jié)省空間,這樣可能會(huì)出現(xiàn)索引的選擇性下降,即基于前綴索引查詢出的相似數(shù)據(jù)可能很多:
ALTER TABLE ds_order ADD KEY (order_no(30)) ;
這里由于訂單號(hào)太長,所以選擇前面30位作為前綴索引,用作訂單號(hào)的查詢,當(dāng)然這里涉及到一個(gè)非常經(jīng)典的業(yè)務(wù)場(chǎng)景,訂單號(hào)機(jī)制。
業(yè)務(wù)場(chǎng)景:前綴索引一個(gè)典型的應(yīng)用場(chǎng)景就是處理訂單號(hào),一個(gè)看似很長的訂單號(hào),其實(shí)包含的信息非常多:
時(shí)間點(diǎn):就是訂單生成的時(shí)間,年月日時(shí)分秒;
標(biāo)識(shí)位:即一個(gè)唯一的UID,保證訂全單號(hào)唯一;
埋點(diǎn)一:在很多業(yè)務(wù)中,在訂單號(hào)記錄產(chǎn)品類目;
埋點(diǎn)二:通常會(huì)標(biāo)識(shí)產(chǎn)品屬性,例如顏色,口味等;
錯(cuò)位符:防止訂單號(hào)被分析,會(huì)隨機(jī)一段錯(cuò)位符號(hào);
如此一段分析下來,實(shí)際訂單號(hào)是非常長的,所以需要引入前綴索引機(jī)制,前綴索引期望使用的索引長度可以篩選整個(gè)列的基數(shù),例如上面的訂單號(hào):
大部分業(yè)務(wù)基于時(shí)間節(jié)點(diǎn)篩選足夠,即索引長度14位;
如果是并發(fā)業(yè)務(wù),很多時(shí)間節(jié)點(diǎn)相同,則索引長度是時(shí)間點(diǎn)+標(biāo)識(shí)位;
注意:如果業(yè)務(wù)允許的情況下,一般要求前綴索引的長度有唯一性,例如上面的時(shí)間和標(biāo)示位。
例如全文索引等,這些用到的場(chǎng)景不多,如果數(shù)據(jù)龐大,又需要檢索等,通常會(huì)選擇強(qiáng)大的搜索中間件來處理。顯式唯一索引,這種也會(huì)在程序上做規(guī)避,避免不友好的異常被拋出。
如何創(chuàng)建最優(yōu)的索引,是一件不容易的事情,同樣在查詢的時(shí)候,是否使用索引也是一件難度極大的事情,經(jīng)驗(yàn)之談:多數(shù)是性能問題暴露的時(shí)候,才會(huì)回頭審視查詢的SQL語句,針對(duì)性能問題,做相應(yīng)的查詢優(yōu)化。
這里直接查詢主鍵索引,MySQL的主鍵一般選擇自增,所以速度非??臁?/p>
EXPLAIN SELECT * FROM ds_order WHERE id=2; EXPLAIN SELECT * FROM ds_order WHERE id=1+1; EXPLAIN SELECT * FROM ds_order WHERE id+1=1;
這里,id=2,id=1+1,MySQL都可以自動(dòng)解析,但是id+1是在索引列上執(zhí)行運(yùn)算,直接導(dǎo)致主鍵索引失效。這里有一個(gè)基本策略,如果非要在單列索引上做操作,可以將該邏輯放在程序中,到MySQL層面,SQL語句越干凈利落越好。
前綴索引的查詢,可以基于Like對(duì)特定長度篩選,或者全訂單號(hào)查詢。
EXPLAIN SELECT * FROM ds_order WHERE order_no LIKE '202008011314158723628732871625%'; EXPLAIN SELECT * FROM ds_order WHERE order_no='20200801131415872362873287162572367';
查詢最麻煩的就是組合索引,或者說查詢條件組合起來,都使用了索引:
EXPLAIN SELECT * FROM ds_order WHERE create_time>'2020-08-01 00:00:00' AND order_state='1';
上述基于組合索引中列的順序,使用了組合索引:state_create_time_index。
EXPLAIN SELECT * FROM ds_order WHERE create_time>'2020-08-01 00:00:00';
上述只使用create_time列,也同樣使用了索引結(jié)構(gòu)。
EXPLAIN SELECT * FROM ds_order WHERE order_state='1';
上述如果只使用order_state條件,則結(jié)果顯示全表掃描。
EXPLAIN SELECT * FROM ds_order WHERE create_time>'2020-08-01 00:00:00' AND order_no LIKE '20200801%';
上述則基于組合索引的create_time列和單列索引order_no保證查詢條件都使用了索引。
通過上面幾個(gè)查詢案例,索引組合索引使用的注意事項(xiàng)如下:
組合索引必須按索引最左列開始查詢;
不能跳過組合字段查詢,這樣無法使用索引。
感謝各位的閱讀,以上就是“怎么合理的使用MySQL索引結(jié)構(gòu)和查詢”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)怎么合理的使用MySQL索引結(jié)構(gòu)和查詢這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。