自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

平臺(tái)數(shù)據(jù)激增破千萬(wàn)下的SQL優(yōu)化

數(shù)據(jù)庫(kù) 其他數(shù)據(jù)庫(kù)
利用Explain,可以快速的分析出缺失的索引,比如檢查Join或者Order by中使用的字段,對(duì)于大表,有無(wú)索引會(huì)有幾十甚至上百倍的效率差異。但索引也并非越多越好,過(guò)多的索引會(huì)對(duì)插入及更新造成比較大的影響。

背景

公司一直維護(hù)著學(xué)生體測(cè)平臺(tái),最近中標(biāo)一個(gè)項(xiàng)目,從原本零零散散的錄入體測(cè)數(shù)據(jù),驟增到幾天內(nèi)上百萬(wàn)的用戶(hù)及上千萬(wàn)的體測(cè)數(shù)據(jù)涌入系統(tǒng),結(jié)果各種異常、慢查、連接拒絕,層出不窮...

過(guò)多的慢sql會(huì)導(dǎo)致數(shù)據(jù)庫(kù)CPU飄升、連接無(wú)法及時(shí)釋放、連接池超出限制,原本幾毫秒的查詢(xún)也遲遲無(wú)法得到響應(yīng),拖垮整個(gè)系統(tǒng),而且系統(tǒng)中使用了消息隊(duì)列,還導(dǎo)致了消息堆積,重啟服務(wù)后,服務(wù)瞬間又被打滿(mǎn),內(nèi)存飄升、頻繁的full GC...之前也整理過(guò)不少sql優(yōu)化的文章,但沒(méi)多少用戶(hù)時(shí),很少去關(guān)注,用戶(hù)驟增時(shí),還是經(jīng)歷了一番“洗禮”,這里記錄一下這幾天的優(yōu)化點(diǎn)。

索引使用

索引優(yōu)化,是一個(gè)老生常談的問(wèn)題了。項(xiàng)目中,利用云平臺(tái)或者配合druid搭建慢sql報(bào)警機(jī)制,可以篩選出執(zhí)行過(guò)慢的語(yǔ)句,然后,再借助explain去分析(有關(guān)explain的用法之前做過(guò)詳細(xì)講解:sql調(diào)優(yōu)之explain關(guān)鍵字詳解)。

利用explain,可以快速的分析出缺失的索引,比如檢查join或者order by中使用的字段,對(duì)于大表,有無(wú)索引會(huì)有幾十甚至上百倍的效率差異。但索引也并非越多越好,過(guò)多的索引會(huì)對(duì)插入及更新造成比較大的影響。

explain之后,type為ALL的,即未使用到索引,多數(shù)還是比較容易處理的。這里順帶列舉一些常見(jiàn)的索引失效場(chǎng)景:

未遵循最左前綴匹配導(dǎo)致索引失效

使用函數(shù)導(dǎo)致索引失效

select * from student where name = left('云端行筆666',4)。

計(jì)算導(dǎo)致索引失效

select * from student where id + 1 = 666。

類(lèi)型轉(zhuǎn)換導(dǎo)致索引失效

select * from student where convert(id,char) = '666'。

不等于(!= 或者<>)索引失效

select * from student where name != "云端行筆"。

like模糊匹配以通配符開(kāi)頭導(dǎo)致索引失效

select * from student where name like "%云端行筆"。

索引字段使用is not null導(dǎo)致失效

select * from student where name is not null。

OR前后存在非索引的列,索引失效

select * from student where id =1 or name = '云端'。

這里列舉兩個(gè)此次優(yōu)化的示例:

示例一:find_in_set

業(yè)務(wù)中有這樣一個(gè)場(chǎng)景,上級(jí)需要看到其所有下級(jí)的數(shù)據(jù),如省及單位需要能查看其下所有市區(qū)縣的學(xué)校。為了方便,之前將學(xué)生所隸屬的學(xué)校以及其上級(jí)省市區(qū)單位,記錄在一個(gè)字段sponsor_ids中,然后通過(guò)find_in_set查詢(xún),如下:

SELECT grade FROM enroll 
WHERE match_id = 60 AND FIND_IN_SET(36, sponsor_ids) 
GROUP BY grade ORDER BY grade

這樣設(shè)計(jì),代碼寫(xiě)起來(lái)很方便,但數(shù)據(jù)量級(jí)大是,查詢(xún)效率極其低下,因?yàn)閒ind_in_set無(wú)法使用索引。

優(yōu)化:事先查詢(xún)所屬下級(jí),然后通過(guò)in查詢(xún)使用索引

SELECT
	s.id
FROM
( SELECT * FROM sponsor WHERE `status` = 1 AND  superior_id IS NOT NULL order by level asc ) s,
  ( SELECT @pid := #{sponsorId} ) pd
WHERE
FIND_IN_SET( superior_id, @pid ) != 0
AND @pid := concat( @pid, ',', id )
SELECT grade FROM enroll 
WHERE match_id = 60 AND  sponsor_id in (36) 
GROUP BY grade ORDER BY grade

雖然在查詢(xún)下級(jí)機(jī)構(gòu)時(shí),也使用了find_in_set,但機(jī)構(gòu)表數(shù)據(jù)量有限,全表掃也無(wú)太大壓力,而enroll報(bào)名表使用in查詢(xún)后,效率明顯提升,由幾秒提升到幾十毫秒。

示例二:聯(lián)合索引

還有一些其他情況,比如:

SELECT sponsor_id, count(sponsor_id) AS sponsor_count FROM enroll 
WHERE match_id = 60 
GROUP BY sponsor_id

這句sql,是用于統(tǒng)計(jì)某次體測(cè)活動(dòng)中,各個(gè)學(xué)校的報(bào)名人數(shù)。設(shè)計(jì)表時(shí)在match_id,sponsor_id上,分別建立的索引,報(bào)名人數(shù)不多時(shí),效率還可以。但報(bào)名人數(shù)幾十萬(wàn)之后,發(fā)現(xiàn)查詢(xún)效率明顯下降,需要幾秒鐘。explain分析如下:

從上述的分析可以看出,查詢(xún)使用了索引,但只用到了match_id這一個(gè)索引,而extra中顯示了using temporary,即使用了中間表進(jìn)行分組,并未用到索引,數(shù)據(jù)量達(dá)到一定量級(jí)后,中間表也會(huì)很大,效率自然也就降低了。

為此,針對(duì)該查詢(xún),建立了match_id和sponsor_id的聯(lián)合索引,explain發(fā)現(xiàn),不在使用中間表,實(shí)際查詢(xún)效率也明顯提升,大概幾百毫秒。(使用到覆蓋索引,不需要回表查詢(xún))

批量插入與更新(避免循環(huán)單條插入)

批量操作,是業(yè)務(wù)中很常見(jiàn)的,比如批量導(dǎo)入學(xué)生,簡(jiǎn)單粗暴的一種做法就是,for循環(huán),然后在循環(huán)中insert,如:

for (int i = 0; i < 50000; i++){
  Student student = new Student("云端行筆" + i,24,"北京市" + i,i + "號(hào)");
  studentMapper.insert(student);
}
<insert id="add" parameterType="com.peng.Student">
  INSERT INTO TEST(ID,Student) VALUES(#{id},#{student});
</insert>

當(dāng)插入百八十條數(shù)據(jù)時(shí),不會(huì)覺(jué)得效有多低,但當(dāng)插入上萬(wàn)條數(shù)據(jù)時(shí),循環(huán)插入可能需要一兩分鐘甚至更久,這就無(wú)法忍受了。正確的打開(kāi)方式:

<insert id="batchAdd" parameterType="java.util.List">
  INSERT INTO TEST(ID,Student)
VALUES
  <foreach collection="list" item="item" index="index" separator="," >
    (#{item.id},#{item.student})
    </foreach>
</insert>

避免全表

業(yè)務(wù)中有這樣一個(gè)需求,導(dǎo)入學(xué)生時(shí),需要對(duì)比學(xué)生編號(hào)是否有重復(fù)。之前的實(shí)現(xiàn)方式是將student表中的所有數(shù)據(jù),全都查出來(lái),加載到內(nèi)存,在內(nèi)存中與導(dǎo)入的數(shù)據(jù)逐條對(duì)比。上百萬(wàn)的數(shù)據(jù),而且還是select *,結(jié)果可想而知...

這種掃全表、select *的做法,回頭來(lái)看,其實(shí)是很初級(jí)的,但實(shí)際開(kāi)發(fā)中,很多時(shí)候,為了圖省事兒,可能就隨手把坑埋下去了...

無(wú)能為力的SQL

業(yè)務(wù)中有這樣一個(gè)場(chǎng)景:學(xué)生參與體測(cè)活動(dòng),需要報(bào)名,因此,除了student學(xué)生表之外,還有一張enroll報(bào)名表,用于記錄學(xué)生在多個(gè)體測(cè)活動(dòng)中的報(bào)名狀態(tài)。業(yè)務(wù)中需要統(tǒng)計(jì)所有未報(bào)名的學(xué)校,思路很簡(jiǎn)單,就是學(xué)生表和報(bào)名表取差集,然后統(tǒng)計(jì)差集中有哪些學(xué)校,SQL如下:

select distinct(s.sponsor_id) from student s
LEFT JOIN enroll e on e.student_id = s.id
where s.status = 1 and e.id is null

問(wèn)題在于,一個(gè)地區(qū)會(huì)有幾百萬(wàn)甚至上千萬(wàn)的學(xué)生,如此龐大的兩張表取交集,太慢了.,優(yōu)化好久也沒(méi)思路...(歡迎評(píng)論區(qū)指點(diǎn)迷津)。SQL無(wú)力了,最終選擇,將未報(bào)名的學(xué)校數(shù)據(jù)提前統(tǒng)計(jì)計(jì)算,放在緩存之中,有學(xué)生狀態(tài)或者報(bào)名狀態(tài)發(fā)生變更,則去更新。該思路也是類(lèi)似于數(shù)據(jù)平臺(tái),千萬(wàn)級(jí)別的數(shù)據(jù),實(shí)時(shí)統(tǒng)計(jì),肯定會(huì)有效率問(wèn)題,因此,往往會(huì)在數(shù)據(jù)服務(wù)中非實(shí)時(shí)計(jì)算。

總結(jié)

以上是平臺(tái)數(shù)據(jù)爆發(fā)期間,優(yōu)化項(xiàng)目是的一些感悟,隨筆一記。

責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2022-10-14 17:24:35

MySQLSQL優(yōu)化

2022-07-05 21:31:21

索引SQL分庫(kù)分表

2017-02-05 17:27:43

2010-03-23 11:55:32

云計(jì)算

2012-09-24 10:20:24

草根應(yīng)用平臺(tái)數(shù)據(jù)

2023-11-30 15:10:20

物聯(lián)網(wǎng)數(shù)據(jù)物聯(lián)網(wǎng)平臺(tái)

2018-03-30 14:30:10

數(shù)據(jù)庫(kù)SQL語(yǔ)句性能優(yōu)化

2018-07-30 14:40:01

MySQLSQL查詢(xún)

2019-05-31 12:03:06

SQLHadoop大數(shù)據(jù)

2022-07-04 23:24:28

sql優(yōu)化監(jiān)控

2012-12-26 09:23:56

數(shù)據(jù)庫(kù)優(yōu)化

2024-03-11 07:38:15

歐拉數(shù)據(jù)血緣數(shù)據(jù)應(yīng)用數(shù)據(jù)治理

2009-12-02 10:33:34

LINQ to SQL

2023-07-26 08:21:33

2023-02-24 16:37:04

MySQL數(shù)據(jù)查詢(xún)數(shù)據(jù)庫(kù)

2015-07-14 17:12:49

2018-07-11 20:07:06

數(shù)據(jù)庫(kù)MySQL索引優(yōu)化

2014-04-09 14:15:23

2016-12-09 09:31:22

HadoopSQL大數(shù)據(jù)

2013-07-15 17:30:24

華為數(shù)據(jù)存儲(chǔ)華為存儲(chǔ)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)