Mysql如何給字符串添加索引(前綴索引)

2021-02-19 潔癖是一隻狗
在日常開發中,我們經常給字符串添加索引,那麼給欄位添加索引有什麼技巧嗎,我們看看下面的例子,我們給一個郵箱添加索引,應該如何添加呢

看看下面這條sql

select *  from user where email ='jiepi@qq.com'

如果我們不添加索引,肯定是要進行全表掃描的,那麼我們如何添加呢有兩種方式
alter table user add index index1(email)alter table user add index index2(email(6))

上面兩種方式都是在添加索引,不同點就是第二種添加的僅僅是郵箱的前綴索引,那麼他的結構表現如下圖

index2每個索引中僅僅存儲了欄位的前6個字符,而index1存儲了整個字符串,我們分別在不同索引下執行下面的語句
select id,name,email  from user where email='zhangsan@qq.com'

在index1中找到符合條件的記錄,獲取id=5

然後使用id=1,在主鍵索引上獲取整行記錄

在index1尋找下一條記錄,直到發現不滿足位置,循環結束

在index2中找到符合條件的值,獲取到id=1

然後在主鍵索引中找到id=1的數據,發現不符合

在index2繼續尋找,id=2,然後在主鍵上找到行記錄,發現不符合

循環上面步驟,直到符合的記錄

我們發現使用index2雖然佔用的空間小,但是他對搜索的性能沒有更好的提高,而是要多掃描幾行記錄。
是不是發現前綴索引不是很好呢,然而並不是的,我們如果把索引的長度修改成8,然後在index2中僅僅找到一條符合記錄,因此只需要掃描一行就夠了。

於是,我們發現選擇合適的前綴長度,既可以節省空間,也可以不用增加更多的查詢成本,

那麼如何選擇合適的前綴長度呢

建立索引之前,我們要關注欄位的區分度,區分度越大,性能越高,意味著重複的值就越少。查看某列的值不同的值

select count(distinct email) as L from user

然後,我們分別取不同長度的前綴,比如我們看一下4-7個字節的前綴索引
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 user

當前使用前綴索引會丟失區分度,索引我們要預定一個可以接受的損失比例,比如5%,然後,計算出L4-L7中,找到不小於L*95%。假設L6,L7,滿足,你就可以選擇長度為6.

前綴索引對覆蓋索引的影響

上面我們分析了,前綴索引影響掃描的行數,其實,他也是會影響覆蓋索引的,正如下面例子

select id,email from user where email='zhangsan@qq.com'select id,name,email from user where email='zhangsan@qq.com'

如果我們只要返回id,email,因此使用index1索引,找到符合記錄利用覆蓋索引,直接返回索引的值,就可以滿足需求,但是如果我們使用index2,即使我們使用email(8)可以找到唯一一行數據,但是我們還是要進行那id的值去主鍵索引判斷是不是email的值,再不濟,我們使用email(18),完全包含欄位的長度,但是我們依然要回表查找主鍵索引,因為系統並確定前綴索引是否有截斷完成信息,

其他方式

對於郵箱類型的欄位,使用前綴索引是一個不錯的選擇,但是我們要是遇到前綴區分度不大的欄位應該怎麼辦呢,

第一種,我們可以使用倒序存儲,如果存儲身份證,一般身份中前6位,一個省的值都是一樣,而後幾位區分度就還可以,索引我們可以使用下面語句查詢

select name from user where id_card=reverse('id_card_string')

第二種,我們使用hash欄位,我們創建一個欄位,直接把身份證的值進行hash,存儲在這個欄位中,同時建立索引,由於可能存在多個身份證可能有一樣的hash值,因此還要判斷id_card的值是否準確

select name from user where id_card_crc=crc32('id_card_string') and id_card='id_card_string'

上面兩種共同點就是不支持範圍查詢,他們的主要區別如下

從佔用的空間方面說,倒序存儲方式在主鍵上不會消耗額外的空間,而hash索引要所創建一個欄位,但是如果倒排存儲長度過長的話,消耗的空間和hash差不多

兩種方式都要使用額外函數,如果從兩個函數的複雜度說的話,reverse函數額外消耗的CPU小點

查詢效率上,hash欄位的方式更穩定一些,雖然可能有衝突,但是這種概率很小,且認為平均掃描一行,而倒序存儲畢竟還要使用前綴索引方式,也就是會增加掃描的行數

如果文章對您有一絲絲幫助,麻煩點個關注,也歡迎轉發點讚,謝謝

相關焦點

  • MySQL索引與索引優化
    innab是聚族索引,數據與索引存儲在一起最左前綴匹配原則。這是常重要、常重要、常重要(重要的事情說三遍)的原則,MySQL會直向右匹配直到遇到範圍查詢(>,<,BETWEEN,LIKE)就停匹配。
  • Christina問我:你都是如何設計索引的?
    , id),MySQL會自動在輔助索引的最後添加上主鍵id,熟悉Oracle資料庫的都知道,索引裡除了索引列還存儲了row_id(代表數據的物理位置,由四部分組成:對象編號+數據文件號+數據塊號+數據行號),我們在創建輔助索引也可以顯示添加主鍵id。
  • MySQL 8.0 中的索引可以隱藏了…
    即可以利用隱藏索引快速測試刪除索引後對 SQL 查詢性能的影響,而無需進行索引刪除、重建操作,如果需要該索引,再設置可見就好了,這在大表測試中無疑非常有用,因為對於大表索引的刪除和重新添加很耗性能,甚至影響表的正常工作。
  • 資料庫面試常見問題:前綴索引、索引下推-開課吧
    資料庫面試1、前綴索引因為可能我們索引的欄位常,這既佔內存空間,也不利於維護。所以我們就想,如果只把很欄位的前的公共部分作為個索引,就會產超級加倍的效果。但是,我們需要注意, order by 不持前綴索引流程是:先計算完整列的選擇性1 select count(distinct col_1)/count(1) from table_1再計算不同前綴度的選擇性
  • 從原理到優化,深入淺出資料庫索引 - 計算機java編程
    而且,只有MyISAM 儲存引擎支持全文索引。(4)創建單列索引這裡需要注意的,subject 的長度為255,但是index4_st索引只有10。這樣做的目的還是為了提高查詢速度。對於字符型的數據,可以不用查詢全部信息,只查詢其前面的若干字符信息。
  • Mysql為啥用B+樹來做索引?
    一、為什麼需要索引?大家都知道,我們讀取數據時要避免全表掃描,那如何避免全表掃描呢?目前科學家給出的目標就是索引。索引就好比一本字典的目錄一樣,有了目錄讀者就不需要翻找全書來找內容。同樣有了索引,資料庫就不用全表掃描了。在一張數據表中不管你建不建索引都會有一個默認索引。
  • 100條MySQL規範,從入門到精通,很實用!
    ,需要將其用單引號括起來)3、資料庫對象的命名要能做到見名識意,並且最後不要超過32個字符4、臨時庫表必須以tmp_為前綴並以日期為後綴,備份表必須以bak_為前綴並以日期(時間戳)為後綴5、所有存儲相同數據的列名和列類型必須一致(一般作為關聯列,如果查詢時關聯列類型不一致會自動進行數據類型隱式轉換,會造成列上的索引失效,導致查詢效率降低)
  • MySQL 資料庫的哈希表-愛可生
    MySQL 的默認索引結構是 B+ 樹,也可以指定索引結構為 HASH 或者 R 樹等其他結構來適應不同的檢索需求。這裡我們來介紹 MySQL 哈希索引。MySQL 哈希索引又基於哈希表(散列表)來實現,所以了解什麼是哈希表對 MySQL 哈希索引的理解至關重要。
  • MySQL 一千個不用 Null 的理由
    Mysql難以優化引用可空列查詢,它會使索引、索引統計和值更加複雜。可空列需要更多的存儲空間,還需要mysql內部進行特殊處理。可空列被索引後,每條記錄都需要一個額外的字節,還能導致MYisam 中固定大小的索引變成可變大小的索引。照此分析,還真不是以訛傳訛,這是有理論依據和出處的。3、給我一個不用 Null 的理由?
  • 後端接口訪問數據查詢如何提高性能?從MySQL、ES、HBASE等技術出發...
    1.1 索引在數據量不是很大時,大多慢查詢可以用索引解決,大多慢查詢也因為索引不合理而產生。MySQL 索引基於 B+ 樹,這句話相信面試都背爛了,接著就可以問最左前綴索引、 B+ 樹和各種樹了。說到最左前綴,實際就是組合索引的使用規則,使用合理組合索引可以有效的提高查詢速度,為什麼呢?因為索引下推。如果查詢條件包含在了組合索引中,比如存在組合索引(a,b),查詢到滿足 a 的記錄後會直接在索引內部判斷 b 是否滿足,減少回表次數。同時,如果查詢的列恰好包含在組合索引中,即為覆蓋索引,無需回表。
  • 為什麼 MongoDB 索引選擇B-樹,而 Mysql 選擇B+樹(精幹總結)
    這個問題是我在看視頻的時候老師提到的,雖然之前知道他們各自的索引結構但是還沒有研究過原因。在網上一搜答案特別多。但是都特別的囉嗦。於是總結了這篇文章。針對我們這個問題的最核心的特點如下:(1)多路,非二叉樹(2)每個節點既保存索引,又保存數據(3)搜索時相當於二分查找在這裡我們假定都已經了解了B樹相關的結構。
  • MySQL中的哥哥表、妹妹欄位,是什麼鬼?
    使用上限:單張表中索引數量不超過5個,單個索引中的欄位數不超過5個;varchar欄位最大值不超過1024;注意:VARCHAR(N)中的N表示字符數而非字節數2. 索引規範索引是資料庫中非常重要的結構,可以加速數據的檢索。
  • 「詳細」MySQL資料庫與JDBC編程
    創建索引:1、自動 當在表上定義主鍵約束、唯一約束、外鍵約束時,系統自動創建對應的索引。 2、手動 CREATE INDEX 索引名 ON 表名(name, pass);刪除索引:1、自動 數據表被刪除時,該表上的索引自動被刪除。
  • Java基礎之字符串及——String
    我們可以用烤串來比喻說明,可以把字符串看作是烤串,烤串上的每一塊肉都相當於是一個字符。把一塊塊肉按照肥瘦相間的順序排列並串起來便成了我們吃的烤串,同理,把多個字符按照一定的順序「串」起來就構成了字符串。
  • 您的包裹「 MySQL靈魂十連」 待籤收
    從節點開啟一個線程(I/O Thread)把自己扮演成 mysql 的客戶端,通過 mysql 協議,請求主節點的二進位日誌文件中的事件 。還可以延伸到由於主從配置不一樣、主庫大事務、從庫壓力過大、網絡震蕩等造成主備延遲,如何避免這個問題?主備切換的時候用可靠性優先原則還是可用性優先原則?如何判斷主庫Crash了?互為主備情況下如何避免主備循環複製?被刪庫跑路了如何正確恢復?(⊙o⊙)… 感覺越來越扯到 DBA 的活兒上去了。
  • 2020火熱的一個索引!快來了解一下吧!
    平時的時候人們快速準確的查詢信息庫中的信息,經常會給表中的欄位添加索引,因為這樣是最快的一種方法了,那麼大家考慮過如何添加索引才能使索引變得更高效嗎,如果說加了索引,索引本身是有序的,所以從磁碟讀的行數本身就是按 age 排序好的。
  • PyTorch官方教程大更新:增加標籤索引,更加新手友好
    PyTorch官方教程大更新:增加標籤索引,更加新手友好 2020-05-17 19:08 來源:澎湃新聞·澎湃號·湃客
  • MySQL優化:定位慢查詢的兩種方法以及使用explain分析SQL
    開啟慢查詢日誌(默認是關閉的):mysql> set global slow_query_log = on;Query OK, 0 rows affected (0.00 sec)設置慢查詢時間限制(查詢時間只要大於這個值都將記錄到慢查詢日誌中,單位:秒):mysql> set global long_query_time = 1;
  • Mysql資料庫部分
    在筆試題最後一般都是有一道關於mysql語句的問題,讓手寫出增、刪、改、查語句,今天我們就學習一下mysql語句。7.2 不要以字符格式聲明數字,要以數字格式聲明字符值。(日期同樣)否則會使索引無效,產生全表掃描。