MySQL怎么給字符串字段加索引
假設(shè),你現(xiàn)在維護(hù)一個(gè)支持郵箱登錄的系統(tǒng),用戶表是這么定義的:
create table SUser( ?ID bigint unsigned primary key, ?email varchar(64), ?... ?)engine=innodb;
由于要使用郵箱登錄,所以業(yè)務(wù)代碼中一定會(huì)出現(xiàn)類似于這樣的語(yǔ)句:
select f1, f2 from SUser where email='xxx';
如果 email 這個(gè)字段上沒(méi)有索引,那么這個(gè)語(yǔ)句就只能做全表掃描。
1)那我可以在郵箱地址這個(gè)字段上面建索引嗎?
MySQL 是支持前綴索引的,可以定義字符串的一部分作為索引
2)如果創(chuàng)建索引的語(yǔ)句不指定前綴長(zhǎng)度,那么會(huì)怎么樣?
索引就會(huì)包含整個(gè)字符串
3)能舉例來(lái)說(shuō)明一下嗎?
alter table SUser add index index1(email); ?或 ?alter table SUser add index index2(email(6));
index1 索引里面,包含了每個(gè)記錄的整個(gè)字符串
index2 索引里面,對(duì)于每個(gè)記錄都是只取前 6 個(gè)字節(jié)
4)這兩種不同的定義在數(shù)據(jù)結(jié)構(gòu)和存儲(chǔ)上有什么區(qū)別呢?
明顯看出email(6) 這個(gè)索引結(jié)構(gòu)占用的空間會(huì)更小
5)email(6) 這個(gè)索引結(jié)構(gòu)有什么缺點(diǎn)嗎?
可能會(huì)增加額外的記錄掃描次數(shù)
6)下面這個(gè)語(yǔ)句,在這兩個(gè)索引定義下分別是怎么執(zhí)行的?
select id,name,email from SUser where email='zhangssxyz@xxx.com';
index1(即 email 整個(gè)字符串的索引結(jié)構(gòu)),執(zhí)行順序
從 index1 索引樹(shù)找到滿足索引值是’zhangssxyz@xxx.com’的這條記錄,取得 ID2 的值;
回表查到主鍵值是 ID2 的行,判斷 email 的值是正確的,將這行記錄加入結(jié)果集;
繼續(xù)在index索引樹(shù)的下一條記錄,發(fā)現(xiàn)已經(jīng)不滿足 email='zhangssxyz@xxx.com’的條件了,循環(huán)結(jié)束。
這個(gè)過(guò)程中,只需要回主鍵索引取一次數(shù)據(jù),所以系統(tǒng)認(rèn)為只掃描了一行。
index2(即 email(6) 索引結(jié)構(gòu)),執(zhí)行順序
從 index2 索引樹(shù)找到滿足索引值是’zhangs’的記錄,找到的第一個(gè)是 ID1;
到主鍵上查到主鍵值是 ID1 的行,判斷出 email 的值不是’zhangssxyz@xxx.com’,這行記錄丟棄;
取 index2 上剛剛查到的位置的下一條記錄,發(fā)現(xiàn)仍然是’zhangs’,取出 ID2,再到 ID 索引上取整行然后判斷,這次值對(duì)了,將這行記錄加入結(jié)果集;
重復(fù)上一步,直到在 idxe2 上取到的值不是’zhangs’時(shí),循環(huán)結(jié)束。
在這個(gè)過(guò)程中,要回主鍵索引取 4 次數(shù)據(jù),也就是掃描了 4 行。
7)通過(guò)上面的對(duì)比,能得出什么結(jié)論?
使用前綴索引后,可能會(huì)導(dǎo)致查詢語(yǔ)句讀數(shù)據(jù)的次數(shù)變多。
8)前綴索引真的一無(wú)是處嗎?
如果我們定義的 index2 不是 email(6) 而是 email(7),那滿足前綴’zhangss’的記錄只有一個(gè),直接就查到 ID2了,只掃描一行就結(jié)束了。
9)那么使用前綴索引有哪些注意事項(xiàng)?
長(zhǎng)度選擇合理
10)當(dāng)要給字符串創(chuàng)建前綴索引時(shí),我咋知道我該用多長(zhǎng)的前綴索引呢?
統(tǒng)計(jì)索引上有多少個(gè)不同的值來(lái)判斷要使用多長(zhǎng)的前綴。
11)怎樣統(tǒng)計(jì)索引上有多少個(gè)不同的值?
select count(distinct email) as L from SUser;
12)拿到了索引對(duì)應(yīng)的有多少個(gè)不同的值之后下一步該做什么?
依次選取不同長(zhǎng)度的前綴來(lái)看這個(gè)值
select ? ?count(distinct left(email,4))as L4, ? ?count(distinct left(email,5))as L5, ? ?count(distinct left(email,6))as L6, ? ?count(distinct left(email,7))as L7, ?from SUser;
然后,在 L4~L7 中,找出第一個(gè)不小于 L * 95% 的值,說(shuō)明通過(guò)這個(gè)索引可以找出百分之95以上的數(shù)據(jù)。
13)前綴索引對(duì)覆蓋索引的影響是什么?
下面這個(gè) SQL 語(yǔ)句:
select id,email from SUser where email='zhangssxyz@xxx.com';
與前面例子中的 SQL 語(yǔ)句
select id,name,email from SUser where email='zhangssxyz@xxx.com';
相比,第一個(gè)語(yǔ)句只要求返回 id 和 email 字段。
如果使用 index1(即 email 整個(gè)字符串的索引結(jié)構(gòu))的話,查email的話就能得到ID,那就不用回表了,這個(gè)就是覆蓋索引。
用 index2(即 email(6) 索引結(jié)構(gòu))的話,就不得不回到 ID 索引再去判斷 email 字段的值。
14)那我把index2 的定義修改為 email(18) 的前綴索引不就行了?
這個(gè)18是你自己定義的,系統(tǒng)不知道18這個(gè)長(zhǎng)度是否已經(jīng)大于我的email長(zhǎng)度,所以它還是會(huì)回表去查一下驗(yàn)證。
總而言之:使用前綴索引就用不上覆蓋索引對(duì)查詢性能的優(yōu)化了
15)對(duì)于類似于郵箱這樣的字段來(lái)說(shuō),使用前綴索引的效果可能還不錯(cuò)。但是,遇到身份證這種前綴的區(qū)分度不夠好的情況時(shí),我們要怎么辦呢?
索引選取的要更長(zhǎng)一些。
但是所以越長(zhǎng)的話,占的磁盤空間更大,相同的一頁(yè)能放下的索引值就變少了,反而會(huì)影響查詢效率。
16)如果我們能夠確定業(yè)務(wù)需求里面只有按照身份證進(jìn)行等值查詢的需求,還有沒(méi)有別的處理方法呢?
既然正過(guò)來(lái)相同的多,那我就把它倒過(guò)來(lái)存。查詢時(shí)候這樣查
select field_list from t where id_card = reverse('input_id_card_string');
使用 的時(shí)候用count(distinct) 方法去做個(gè)驗(yàn)證
使用 hash 字段。在表上再創(chuàng)建一個(gè)整數(shù)字段,來(lái)保存身份證的校驗(yàn)碼,同時(shí)在這個(gè)字段上創(chuàng)建索引。
alter table t add id_card_crc int unsigned, add index(id_card_crc);
每次插入新記錄的時(shí)候,都同時(shí)用 crc32() 這個(gè)函數(shù)得到校驗(yàn)碼填到這個(gè)新字段。由于校驗(yàn)碼可能存在沖突,也就是說(shuō)兩個(gè)不同的身份證號(hào)通過(guò) crc32() 函數(shù)得到的結(jié)果可能是相同的,所以你的查詢語(yǔ)句 where 部分要判斷 id_card 的值是否精確相同。
select field_list from t where id_card_crc=crc32('input_id_card_string') and id_card='input_id_card_string'
這樣,索引的長(zhǎng)度變成了 4 個(gè)字節(jié)(int類型),比原來(lái)小了很多
17)使用倒序存儲(chǔ)和使用 hash 字段這兩種方法有什么異同點(diǎn)?
相同點(diǎn):都不支持范圍查詢
倒序存儲(chǔ)的字段上創(chuàng)建的索引是按照倒序字符串的方式排序的,已經(jīng)沒(méi)有辦法利用索引方式查出身份證號(hào)碼在[ID_X, ID_Y]的所有市民了。同樣地,hash 字段的方式也只能支持等值查詢。
區(qū)別
從占用的額外空間來(lái)看,倒序存儲(chǔ)方式在主鍵索引上,不會(huì)消耗額外的存儲(chǔ)空間,而 hash 字段方法需要增加一個(gè)字段。當(dāng)然,倒序存儲(chǔ)方式使用 4 個(gè)字節(jié)的前綴長(zhǎng)度應(yīng)該是不夠的,如果再長(zhǎng)一點(diǎn),這個(gè)消耗跟額外這個(gè) hash 字段也差不多抵消了。
在 CPU 消耗方面,倒序方式每次寫和讀的時(shí)候,都需要額外調(diào)用一次 reverse 函數(shù),而 hash 字段的方式需要額外調(diào)用一次 crc32() 函數(shù)。如果只從這兩個(gè)函數(shù)的計(jì)算復(fù)雜度來(lái)看的話,reverse 函數(shù)額外消耗的 CPU 資源會(huì)更小些。
從查詢效率上看,使用 hash 字段方式的查詢性能相對(duì)更穩(wěn)定一些。因?yàn)?crc32 算出來(lái)的值雖然有沖突的概率,但是概率非常小,可以認(rèn)為每次查詢的平均掃描行數(shù)接近 1。而倒序存儲(chǔ)方式畢竟還是用的前綴索引的方式,也就是說(shuō)還是會(huì)增加掃描行數(shù)。
案例:如果你在維護(hù)一個(gè)學(xué)校的學(xué)生信息數(shù)據(jù)庫(kù),學(xué)生登錄名的統(tǒng)一格式是”學(xué)號(hào) @gmail.com", 而學(xué)號(hào)的規(guī)則是:十五位的數(shù)字,其中前三位是所在城市編號(hào)、第四到第六位是學(xué)校編號(hào)、第七位到第十位是入學(xué)年份、最后五位是順序編號(hào)。
18)系統(tǒng)登錄的時(shí)候都需要學(xué)生輸入登錄名和密碼,驗(yàn)證正確后才能繼續(xù)使用系統(tǒng)。就只考慮登錄驗(yàn)證這個(gè)行為的話,你會(huì)怎么設(shè)計(jì)這個(gè)登錄名的索引呢?
一個(gè)學(xué)校每年預(yù)估2萬(wàn)新生,50年才100萬(wàn)記錄,能節(jié)省多少空間,直接全字段索引。省去了開(kāi)發(fā)轉(zhuǎn)換及局限性風(fēng)險(xiǎn),碰到超大量迫不得已再用后兩種辦法
實(shí)際操作上直接全字段索引就行了,一個(gè)學(xué)校數(shù)據(jù)庫(kù)的數(shù)據(jù)量和查詢壓力都不會(huì)大到哪兒去。 如果單從優(yōu)化數(shù)據(jù)表的角度: \1. 后綴@gmail可以單獨(dú)一個(gè)字段來(lái)存,或者用業(yè)務(wù)代碼來(lái)保證, \2. 城市編號(hào)和學(xué)校編號(hào)估計(jì)也不會(huì)變,也可以用業(yè)務(wù)代碼來(lái)配置 \3. 然后直接存年份和順序編號(hào)就行了,這個(gè)字段可以全字段索引
到此這篇關(guān)于MySQL怎么給字符串字段加索引的文章就介紹到這了,更多相關(guān)MySQL字符串字段加索引內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mysql 正則表達(dá)式查詢含有非數(shù)字和字符的記錄
這篇文章主要介紹了mysql 正則表達(dá)式查詢含有非數(shù)字和字符的記錄的相關(guān)資料,需要的朋友可以參考下2016-12-12Mysql中文數(shù)據(jù)變成問(wèn)號(hào)的解決辦法
mysql存進(jìn)去的數(shù)據(jù),有中文的字段變成了???的樣式,所以本文給大家詳細(xì)介紹了Mysql中文數(shù)據(jù)變成問(wèn)號(hào)的解決辦法,文中通過(guò)圖文結(jié)合的方式講解的非常詳細(xì),需要的朋友可以參考下2023-12-12MySQL單表記錄數(shù)過(guò)大的優(yōu)化方法
當(dāng)MySQL單表記錄數(shù)過(guò)大時(shí),采取合理的優(yōu)化策略是保障系統(tǒng)高性能的關(guān)鍵,本博客詳細(xì)介紹了索引優(yōu)化、分區(qū)表、垂直拆分、水平拆分等多種優(yōu)化手段,并提供了詳細(xì)的代碼示例,感興趣的朋友一起看看吧2024-01-01單個(gè)select語(yǔ)句實(shí)現(xiàn)MySQL查詢統(tǒng)計(jì)次數(shù)
MySQL中查詢統(tǒng)計(jì)次數(shù)往往語(yǔ)句寫法很復(fù)雜,下文就教您一個(gè)只用單個(gè)select語(yǔ)句就實(shí)現(xiàn)的方法,希望對(duì)您能夠有所幫助2014-05-05

Navicat連接MySQL提示1045錯(cuò)誤解決(重置MySQL密碼)

MySQL5.7安裝過(guò)程并重置root密碼的方法(shell 腳本)