MySQL面試題-SQL優(yōu)化

1. SQL的生命周期执隧?

應(yīng)用服務(wù)器與數(shù)據(jù)庫服務(wù)器建立一個(gè)連接

數(shù)據(jù)庫進(jìn)程拿到請(qǐng)求sql

解析并生成執(zhí)行計(jì)劃忌愚,執(zhí)行

讀取數(shù)據(jù)到內(nèi)存并進(jìn)行邏輯處理

通過步驟一的連接曲管,發(fā)送結(jié)果到客戶端

關(guān)掉連接,釋放資源


2. 大表數(shù)據(jù)查詢硕糊,怎么優(yōu)化

優(yōu)化shema院水、sql語句+索引;

第二加緩存简十,memcached, redis檬某;

主從復(fù)制,讀寫分離勺远;

垂直拆分橙喘,根據(jù)你模塊的耦合度,將一個(gè)大的系統(tǒng)分為多個(gè)小的系統(tǒng)胶逢,也就是分布式系統(tǒng)厅瞎;

水平切分,針對(duì)數(shù)據(jù)量大的表初坠,這一步最麻煩和簸,最能考驗(yàn)技術(shù)水平,要選擇一個(gè)合理的sharding key, 為了有好的查詢效率碟刺,表結(jié)構(gòu)也要改動(dòng)锁保,做一定的冗余,應(yīng)用也要改半沽,sql中盡量帶sharding key爽柒,將數(shù)據(jù)定位到限定的表上去查,而不是掃描全部的表者填;

3. 超大分頁怎么處理浩村?

超大的分頁一般從兩個(gè)方向上來解決.

數(shù)據(jù)庫層面,這也是我們主要集中關(guān)注的(雖然收效沒那么大),類似于select * from table where age > 20 limit 1000000,10這種查詢其實(shí)也是有可以優(yōu)化的余地的. 這條語句需要load1000000數(shù)據(jù)然后基本上全部丟棄,只取10條當(dāng)然比較慢. 當(dāng)時(shí)我們可以修改為select * from table where id in (select id from table where age > 20 limit 1000000,10).這樣雖然也load了一百萬的數(shù)據(jù),但是由于索引覆蓋,要查詢的所有字段都在索引中,所以速度會(huì)很快. 同時(shí)如果ID連續(xù)的好,我們還可以select * from table where id > 1000000 limit 4,效率也是不錯(cuò)的,優(yōu)化的可能性有許多種,但是核心思想都一樣,就是減少load的數(shù)據(jù).

從需求的角度減少這種請(qǐng)求…主要是不做類似的需求(直接跳轉(zhuǎn)到幾百萬頁之后的具體某一頁.只允許逐頁查看或者按照給定的路線走,這樣可預(yù)測,可緩存)以及防止ID泄漏且連續(xù)被人惡意攻擊.

解決超大分頁,其實(shí)主要是靠緩存,可預(yù)測性的提前查到內(nèi)容,緩存至redis等k-V數(shù)據(jù)庫中,直接返回即可.

在阿里巴巴《Java開發(fā)手冊(cè)》中,對(duì)超大分頁的解決辦法是類似于上面提到的第一種.

【推薦】利用延遲關(guān)聯(lián)或者子查詢優(yōu)化超多分頁場景。

說明:MySQL并不是跳過offset行占哟,而是取offset+N行心墅,然后返回放棄前offset行,返回N行榨乎,那當(dāng)offset特別大的時(shí)候怎燥,效率就非常的低下,要么控制返回的總頁數(shù)蜜暑,要么對(duì)超過特定閾值的頁數(shù)進(jìn)行SQL改寫铐姚。

正例:先快速定位需要獲取的id段,然后再關(guān)聯(lián):

SELECT a.* FROM 表1 a, (select id from 表1 where 條件 LIMIT 100000,20 ) b where a.id=b.id

![](https://user-gold-cdn.xitu.io/2020/4/6/1714e4746e236ebe?w=1440&h=800&f=jpeg&s=209737)

5. mysql 分頁

LIMIT 子句可以被用于強(qiáng)制 SELECT 語句返回指定的記錄數(shù)史煎。LIMIT 接受一個(gè)或兩個(gè)數(shù)字參數(shù)谦屑。參數(shù)必須是一個(gè)整數(shù)常量驳糯。如果給定兩個(gè)參數(shù),第一個(gè)參數(shù)指定第一個(gè)返回記錄行的偏移量氢橙,第二個(gè)參數(shù)指定返回記錄行的最大數(shù)目酝枢。初始記錄行的偏移量是 0(而不是 1)

mysql> SELECT * FROM table LIMIT 5,10; // 檢索記錄行 6-15

為了檢索從某一個(gè)偏移量到記錄集的結(jié)束所有的記錄行,可以指定第二個(gè)參數(shù)為 -1:

mysql> SELECT * FROM table LIMIT 95,-1; // 檢索記錄行 96-last.

如果只給定一個(gè)參數(shù)悍手,它表示返回最大的記錄行數(shù)目:

mysql> SELECT * FROM table LIMIT 5; //檢索前 5 個(gè)記錄行

換句話說帘睦,LIMIT n 等價(jià)于 LIMIT 0,n。


6. 慢查詢?nèi)罩?/p>

用于記錄執(zhí)行時(shí)間超過某個(gè)臨界值的SQL日志坦康,用于快速定位慢查詢竣付,為我們的優(yōu)化做參考。

開啟慢查詢?nèi)罩?/p>

配置項(xiàng):slow_query_log

可以使用show variables like ‘slov_query_log’查看是否開啟滞欠,如果狀態(tài)值為OFF古胆,可以使用set GLOBAL slow_query_log = on來開啟,它會(huì)在datadir下產(chǎn)生一個(gè)xxx-slow.log的文件筛璧。

設(shè)置臨界時(shí)間

配置項(xiàng):long_query_time

查看:show VARIABLES like 'long_query_time'逸绎,單位秒

設(shè)置:set long_query_time=0.5

實(shí)操時(shí)應(yīng)該從長時(shí)間設(shè)置到短的時(shí)間,即將最慢的SQL優(yōu)化掉

查看日志夭谤,一旦SQL超過了我們?cè)O(shè)置的臨界時(shí)間就會(huì)被記錄到xxx-slow.log中

7. 關(guān)心過業(yè)務(wù)系統(tǒng)里面的sql耗時(shí)嗎棺牧?統(tǒng)計(jì)過慢查詢嗎?對(duì)慢查詢都怎么優(yōu)化過朗儒?

在業(yè)務(wù)系統(tǒng)中颊乘,除了使用主鍵進(jìn)行的查詢,其他的我都會(huì)在測試庫上測試其耗時(shí)醉锄,慢查詢的統(tǒng)計(jì)主要由運(yùn)維在做乏悄,會(huì)定期將業(yè)務(wù)中的慢查詢反饋給我們。

慢查詢的優(yōu)化首先要搞明白慢的原因是什么恳不?是查詢條件沒有命中索引纲爸?是load了不需要的數(shù)據(jù)列?還是數(shù)據(jù)量太大妆够?

所以優(yōu)化也是針對(duì)這三個(gè)方向來的,

首先分析語句负蚊,看看是否load了額外的數(shù)據(jù)神妹,可能是查詢了多余的行并且拋棄掉了,可能是加載了許多結(jié)果中并不需要的列家妆,對(duì)語句進(jìn)行分析以及重寫鸵荠。

分析語句的執(zhí)行計(jì)劃,然后獲得其使用索引的情況伤极,之后修改語句或者修改索引蛹找,使得語句可以盡可能的命中索引姨伤。

如果對(duì)語句的優(yōu)化已經(jīng)無法進(jìn)行,可以考慮表中的數(shù)據(jù)量是否太大庸疾,如果是的話可以進(jìn)行橫向或者縱向的分表乍楚。

8. 為什么要盡量設(shè)定一個(gè)主鍵?

主鍵是數(shù)據(jù)庫確保數(shù)據(jù)行在整張表唯一性的保障届慈,即使業(yè)務(wù)上本張表沒有主鍵徒溪,也建議添加一個(gè)自增長的ID列作為主鍵。設(shè)定了主鍵之后金顿,在后續(xù)的刪改查的時(shí)候可能更加快速以及確保操作數(shù)據(jù)范圍安全臊泌。

9. 主鍵使用自增ID還是UUID?

推薦使用自增ID揍拆,不要使用UUID渠概。

因?yàn)樵贗nnoDB存儲(chǔ)引擎中,主鍵索引是作為聚簇索引存在的嫂拴,也就是說播揪,主鍵索引的B+樹葉子節(jié)點(diǎn)上存儲(chǔ)了主鍵索引以及全部的數(shù)據(jù)(按照順序),如果主鍵索引是自增ID顷牌,那么只需要不斷向后排列即可剪芍,如果是UUID,由于到來的ID與原來的大小不確定窟蓝,會(huì)造成非常多的數(shù)據(jù)插入罪裹,數(shù)據(jù)移動(dòng),然后導(dǎo)致產(chǎn)生很多的內(nèi)存碎片运挫,進(jìn)而造成插入性能的下降状共。

總之,在數(shù)據(jù)量大一些的情況下谁帕,用自增主鍵性能會(huì)好一些峡继。

關(guān)于主鍵是聚簇索引,如果沒有主鍵匈挖,InnoDB會(huì)選擇一個(gè)唯一鍵來作為聚簇索引碾牌,如果沒有唯一鍵,會(huì)生成一個(gè)隱式的主鍵儡循。

10. 字段為什么要求定義為not null舶吗?

null值會(huì)占用更多的字節(jié),且會(huì)在程序中造成很多與預(yù)期不符的情況择膝。

11. 如果要存儲(chǔ)用戶的密碼散列誓琼,應(yīng)該使用什么字段進(jìn)行存儲(chǔ)?

密碼散列,鹽腹侣,用戶身份證號(hào)等固定長度的字符串應(yīng)該使用char而不是varchar來存儲(chǔ)叔收,這樣可以節(jié)省空間且提高檢索效率。

![](https://user-gold-cdn.xitu.io/2020/4/6/1714e47972fe4c31?w=500&h=313&f=jpeg&s=16065)

12. 優(yōu)化查詢過程中的數(shù)據(jù)訪問

訪問數(shù)據(jù)太多導(dǎo)致查詢性能下降

確定應(yīng)用程序是否在檢索大量超過需要的數(shù)據(jù)傲隶,可能是太多行或列

確認(rèn)MySQL服務(wù)器是否在分析大量不必要的數(shù)據(jù)行

避免犯如下SQL語句錯(cuò)誤

查詢不需要的數(shù)據(jù)饺律。解決辦法:使用limit解決

多表關(guān)聯(lián)返回全部列。解決辦法:指定列名

總是返回全部列伦籍。解決辦法:避免使用SELECT *

重復(fù)查詢相同的數(shù)據(jù)蓝晒。解決辦法:可以緩存數(shù)據(jù),下次直接讀取緩存

是否在掃描額外的記錄帖鸦。解決辦法:

使用explain進(jìn)行分析芝薇,如果發(fā)現(xiàn)查詢需要掃描大量的數(shù)據(jù),但只返回少數(shù)的行作儿,可以通過如下技巧去優(yōu)化:

使用索引覆蓋掃描洛二,把所有的列都放到索引中,這樣存儲(chǔ)引擎不需要回表獲取對(duì)應(yīng)行就可以返回結(jié)果攻锰。

改變數(shù)據(jù)庫和表的結(jié)構(gòu)晾嘶,修改數(shù)據(jù)表范式

重寫SQL語句,讓優(yōu)化器可以以更優(yōu)的方式執(zhí)行查詢娶吞。

13. 優(yōu)化長難的查詢語句

一個(gè)復(fù)雜查詢還是多個(gè)簡單查詢

MySQL內(nèi)部每秒能掃描內(nèi)存中上百萬行數(shù)據(jù)垒迂,相比之下,響應(yīng)數(shù)據(jù)給客戶端就要慢得多

使用盡可能小的查詢是好的妒蛇,但是有時(shí)將一個(gè)大的查詢分解為多個(gè)小的查詢是很有必要的机断。

切分查詢

將一個(gè)大的查詢分為多個(gè)小的相同的查詢

一次性刪除1000萬的數(shù)據(jù)要比一次刪除1萬,暫停一會(huì)的方案更加損耗服務(wù)器開銷绣夺。

分解關(guān)聯(lián)查詢吏奸,讓緩存的效率更高。

執(zhí)行單個(gè)查詢可以減少鎖的競爭陶耍。

在應(yīng)用層做關(guān)聯(lián)更容易對(duì)數(shù)據(jù)庫進(jìn)行拆分奋蔚。

查詢效率會(huì)有大幅提升。

較少冗余記錄的查詢烈钞。

14. 優(yōu)化特定類型的查詢語句

count(*)會(huì)忽略所有的列泊碑,直接統(tǒng)計(jì)所有列數(shù),不要使用count(列名)

MyISAM中毯欣,沒有任何where條件的count(*)非扯旯罚快。

當(dāng)有where條件時(shí)仪媒,MyISAM的count統(tǒng)計(jì)不一定比其它引擎快。

可以使用explain查詢近似值,用近似值替代count(*)

增加匯總表

使用緩存


15. 優(yōu)化關(guān)聯(lián)查詢

確定ON或者USING子句中是否有索引算吩。

確保GROUP BY和ORDER BY只有一個(gè)表中的列留凭,這樣MySQL才有可能使用索引。

16. 優(yōu)化子查詢

用關(guān)聯(lián)查詢替代

優(yōu)化GROUP BY和DISTINCT

這兩種查詢據(jù)可以使用索引來優(yōu)化偎巢,是最有效的優(yōu)化方法

關(guān)聯(lián)查詢中蔼夜,使用標(biāo)識(shí)列分組的效率更高

如果不需要ORDER BY,進(jìn)行GROUP BY時(shí)加ORDER BY NULL压昼,MySQL不會(huì)再進(jìn)行文件排序求冷。

WITH ROLLUP超級(jí)聚合,可以挪到應(yīng)用程序處理

17. 優(yōu)化LIMIT分頁

LIMIT偏移量大的時(shí)候窍霞,查詢效率較低

可以記錄上次查詢的最大ID匠题,下次查詢時(shí)直接根據(jù)該ID來查詢

18. 優(yōu)化UNION查詢

UNION ALL的效率高于UNION

![](https://user-gold-cdn.xitu.io/2020/4/6/1714e48e7de624e3?w=3540&h=2360&f=jpeg&s=997676)

19. 優(yōu)化WHERE子句

解題方法

對(duì)于此類考題,先說明如何定位低效SQL語句但金,然后根據(jù)SQL語句可能低效的原因做排查韭山,先從索引著手,如果索引沒有問題冷溃,考慮以上幾個(gè)方面钱磅,數(shù)據(jù)訪問的問題,長難查詢句的問題還是一些特定類型優(yōu)化的問題似枕,逐一回答盖淡。

SQL語句優(yōu)化的一些方法?

1.對(duì)查詢進(jìn)行優(yōu)化凿歼,應(yīng)盡量避免全表掃描褪迟,首先應(yīng)考慮在 where 及 order by 涉及的列上建立索引。

2.應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行 null 值判斷毅往,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描牵咙,如:

select id from t where num is null

-- 可以在num上設(shè)置默認(rèn)值0,確保表中num列沒有null值攀唯,然后這樣查詢:

select id from t where num=

3.應(yīng)盡量避免在 where 子句中使用!=或<>操作符洁桌,否則引擎將放棄使用索引而進(jìn)行全表掃描。

4.應(yīng)盡量避免在 where 子句中使用or 來連接條件侯嘀,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描另凌,如:

select id from t where num=10 or num=20

-- 可以這樣查詢:

select id from t where num=10 union all select id from t where num=20

5.in 和 not in 也要慎用,否則會(huì)導(dǎo)致全表掃描戒幔,如:

select id from t where num in(1,2,3)

-- 對(duì)于連續(xù)的數(shù)值吠谢,能用 between 就不要用 in 了:

select id from t where num between 1 and 3

6.下面的查詢也將導(dǎo)致全表掃描:select id from t where name like ‘%李%’若要提高效率,可以考慮全文檢索诗茎。

7.如果在 where 子句中使用參數(shù)工坊,也會(huì)導(dǎo)致全表掃描。因?yàn)镾QL只有在運(yùn)行時(shí)才會(huì)解析局部變量,但優(yōu)化程序不能將訪問計(jì)劃的選擇推遲到運(yùn)行時(shí)王污;它必須在編譯時(shí)進(jìn)行選擇罢吃。然 而,如果在編譯時(shí)建立訪問計(jì)劃昭齐,變量的值還是未知的尿招,因而無法作為索引選擇的輸入項(xiàng)。如下面語句將進(jìn)行全表掃描:

select id from t where num=@num

-- 可以改為強(qiáng)制查詢使用索引:

select id from t with(index(索引名)) where num=@num

8.應(yīng)盡量避免在 where 子句中對(duì)字段進(jìn)行表達(dá)式操作阱驾,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描就谜。如:

select id from t where num/2=100

-- 應(yīng)改為:

select id from t where num=100*2

9.應(yīng)盡量避免在where子句中對(duì)字段進(jìn)行函數(shù)操作,這將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描里覆。如:

select id from t where substring(name,1,3)=’abc’

-- name以abc開頭的id應(yīng)改為:

select id from t where name like ‘a(chǎn)bc%’

10.不要在 where 子句中的“=”左邊進(jìn)行函數(shù)丧荐、算術(shù)運(yùn)算或其他表達(dá)式運(yùn)算,否則系統(tǒng)將可能無法正確使用索引租谈。

小編分類整理了許多java進(jìn)階學(xué)習(xí)材料和BAT面試題篮奄,需要資料的請(qǐng)加QQ群:731611386就能領(lǐng)取2019年java進(jìn)階學(xué)習(xí)資料和BAT面試題以及《EffectiveJava》(第3版)電子版書籍。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末割去,一起剝皮案震驚了整個(gè)濱河市窟却,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌呻逆,老刑警劉巖夸赫,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異咖城,居然都是意外死亡茬腿,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門宜雀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來切平,“玉大人,你說我怎么就攤上這事辐董°财罚” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵简烘,是天一觀的道長苔严。 經(jīng)常有香客問我,道長孤澎,這世上最難降的妖魔是什么届氢? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮覆旭,結(jié)果婚禮上退子,老公的妹妹穿的比我還像新娘岖妄。我一直安慰自己,他們只是感情好寂祥,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布衣吠。 她就那樣靜靜地躺著,像睡著了一般壤靶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惊搏,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天贮乳,我揣著相機(jī)與錄音,去河邊找鬼恬惯。 笑死向拆,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的酪耳。 我是一名探鬼主播浓恳,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼碗暗!你這毒婦竟也來了颈将?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤言疗,失蹤者是張志新(化名)和其女友劉穎晴圾,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體噪奄,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡死姚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了勤篮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片都毒。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖碰缔,靈堂內(nèi)的尸體忽然破棺而出账劲,到底是詐尸還是另有隱情,我是刑警寧澤手负,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布涤垫,位于F島的核電站,受9級(jí)特大地震影響竟终,放射性物質(zhì)發(fā)生泄漏蝠猬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一统捶、第九天 我趴在偏房一處隱蔽的房頂上張望榆芦。 院中可真熱鬧柄粹,春花似錦、人聲如沸匆绣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽崎淳。三九已至堪夭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拣凹,已是汗流浹背森爽。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嚣镜,地道東北人爬迟。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像菊匿,于是被迫代替她去往敵國和親付呕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容