面試問我SQL回表?我瞬間蒙了
我們最近在看關(guān)于Mysql 的相關(guān)知識(shí),也和現(xiàn)在面試的小伙伴們做了一些采訪,問到了一些相關(guān)的面試題,說實(shí)話,現(xiàn)在面試問的是越來越復(fù)雜了,很多時(shí)候也不從基礎(chǔ)問了,直接項(xiàng)目走起,然后深挖項(xiàng)目中的一些問題,接著就是數(shù)據(jù)庫中的相關(guān)問題,今天了不起來和大家一起聊一下關(guān)于 Mysql 幾個(gè)經(jīng)常問,但是卻讓人很蒙圈的面試題。
索引覆蓋
在面試的時(shí)候,面試官很多會(huì)提問道優(yōu)化SQL,至于怎么優(yōu)化,了不起就不用再繼續(xù)贅述這個(gè)問題,我們往下延伸,你了解索引覆蓋么?
索引覆蓋(Covering Index)或稱為覆蓋索引,是數(shù)據(jù)庫中的一種優(yōu)化手段。
當(dāng)我們執(zhí)行一個(gè)SQL查詢時(shí),如果只需要查詢某幾個(gè)字段的值,并且這幾個(gè)字段的數(shù)據(jù)都已經(jīng)被包含在某一個(gè)索引中(而不是全表掃描),那么數(shù)據(jù)庫引擎就會(huì)直接通過這個(gè)索引來取得數(shù)據(jù),而無需再回表查詢,從而大大減少了I/O操作,提高了查詢效率。
索引覆蓋的優(yōu)點(diǎn)就比如有:
- 減少I/O次數(shù):因?yàn)橥ㄟ^覆蓋索引可以直接獲取數(shù)據(jù),所以不需要再回表查詢,從而減少了I/O次數(shù)。
- 提高查詢速度:由于減少了I/O操作,查詢速度自然也得到了提高。
- 索引的選擇性:選擇性是指不重復(fù)的索引值與數(shù)據(jù)表的總記錄數(shù)的比值。選擇性越高,通過索引篩選出的數(shù)據(jù)就越少,從而提高了查詢效率。
這個(gè)我們就牽扯到回表查詢了?面試官一般就會(huì)套路的繼續(xù)往下問,那你知道回表操作么?
SQL回表
那么什么是 SQL 回表呢?
SQL回表,在MySQL數(shù)據(jù)庫特別是InnoDB存儲(chǔ)引擎中,是一個(gè)重要的概念。
SQL回表是指在使用非聚簇索引(也稱為輔助索引或二級(jí)索引)進(jìn)行查詢時(shí),由于非聚簇索引中只存儲(chǔ)了索引字段的值和對(duì)應(yīng)的主鍵(聚簇索引)鍵值,因此,如果需要獲取非索引列的數(shù)據(jù),則需要根據(jù)主鍵(聚簇索引)中的鍵值去查找實(shí)際的數(shù)據(jù)行。這個(gè)過程被稱為“回表”。
回表的原理
- 非聚簇索引結(jié)構(gòu):非聚簇索引的葉子節(jié)點(diǎn)存儲(chǔ)的是(索引列的值,主鍵的值)。
- 查詢過程:當(dāng)使用非聚簇索引進(jìn)行查詢時(shí),首先通過非聚簇索引找到滿足條件的主鍵鍵值。然后,根據(jù)這些主鍵鍵值,再回到聚簇索引(主鍵索引)中查找完整的數(shù)據(jù)行。
假設(shè)有一個(gè)用戶表users,包含id(主鍵)、name和age三個(gè)字段,其中在name字段上建立了非聚簇索引。
執(zhí)行查詢SELECT * FROM users WHERE name='Tom'時(shí),會(huì)發(fā)生回表。因?yàn)槭紫葧?huì)通過name上的非聚簇索引找到滿足條件的id,然后再根據(jù)這些id回到聚簇索引中查找完整的用戶數(shù)據(jù)。
而查詢SELECT id, name FROM users WHERE name='Tom'則不會(huì)回表,因?yàn)樗璧臄?shù)據(jù)都在非聚簇索引中可以找到。
而回表操作會(huì)增加I/O次數(shù),從而可能影響查詢性能。特別是在大表和復(fù)雜查詢場(chǎng)景下,回表操作可能成為性能瓶頸。
為了減少回表操作,可以考慮將需要查詢的字段加入到索引中,形成復(fù)合索引(也稱為聯(lián)合索引或覆蓋索引)。這樣,查詢時(shí)就可以直接從索引中獲取到需要的數(shù)據(jù),而無需回表。
所以,建立索引的時(shí)候,我們要非常注意,并不是說索引不好,而是說要會(huì)加才可以。
索引的最左匹配原則
有的時(shí)候,我們建立索引大部分都不會(huì)只是單獨(dú)的一個(gè)字段,所以就有了復(fù)合索引。
索引的最左匹配原則(Leftmost Prefix Rule) 主要是在使用復(fù)合索引(也稱為多列索引或多字段索引)時(shí)的一個(gè)關(guān)鍵概念。這個(gè)原則指出,當(dāng)使用復(fù)合索引進(jìn)行查詢時(shí),查詢條件應(yīng)該盡可能地從索引的最左邊開始匹配,這樣索引才能被有效地使用。
當(dāng)你基于復(fù)合索引進(jìn)行查詢時(shí),查詢條件必須包含索引的最左邊的一列或多列,以便索引能夠被有效地使用。例如,如果你有一個(gè)基于(last_name, first_name)的復(fù)合索引,以下查詢可以有效地使用這個(gè)索引:
查詢基于last_name:SELECT * FROM employees WHERE last_name = 'Smith';
查詢基于last_name和first_name:SELECT * FROM employees WHERE last_name = 'Smith' AND first_name = 'John'; 但是,以下查詢則不能有效地使用這個(gè)索引(因?yàn)樗鼪]有包含索引的最左邊的列l(wèi)ast_name):
查詢僅基于first_name:SELECT * FROM employees WHERE first_name = 'John';
在創(chuàng)建復(fù)合索引時(shí),列的順序很重要。你應(yīng)該將最常用于查詢條件的列放在索引的最左邊。例如,如果你經(jīng)?;趌ast_name進(jìn)行查詢,但很少基于first_name進(jìn)行查詢,那么你應(yīng)該創(chuàng)建一個(gè)基于(last_name, first_name)的索引,而不是基于(first_name, last_name)的索引。
雖然最左匹配原則是一個(gè)重要的概念,但并不意味著你必須始終遵循它。在實(shí)際應(yīng)用中,你需要根據(jù)查詢的需求和數(shù)據(jù)的分布來決定是否使用復(fù)合索引以及索引的列順序。
你學(xué)會(huì)了么?