首頁 資料庫 mysql教程 MySQL如何為字串欄位加索引

MySQL如何為字串欄位加索引

May 28, 2023 pm 02:38 PM
mysql 字串

假設,你現在維護一個支援郵箱登入的系統,用戶表是這麼定義的:

create table SUser(
 ID bigint unsigned primary key,
 email varchar(64), 
 ... 
 )engine=innodb;
登入後複製

由於要使用郵箱登錄,所以業務碼中一定會出現類似這樣的語句:

select f1, f2 from SUser where email='xxx';
登入後複製

如果email 這個欄位上沒有索引,那麼這個語句就只能做全表掃描。

1)那我可以在郵件地址這個欄位上面建立索引嗎?

  • MySQL 是支援前綴索引的,可以定義字串的一部分作為索引

2)如果建立索引的語句不指定前綴長度,那麼會怎麼樣?

  • #索引就會包含整個字串

#3)能舉例來說明嗎?

alter table SUser add index index1(email);
 或
 alter table SUser add index index2(email(6));
登入後複製
  • index1 索引裡面,包含了每個記錄的整個字串

  • index2 索引裡面,對於每個記錄都是只取前6 個位元組

4)這兩個不同的定義在資料結構和儲存上有什麼差別呢?

MySQL如何為字串欄位加索引

MySQL如何為字串欄位加索引

明顯看出email(6) 這個索引結構所佔用的空間會更小

#5)email(6) 這個索引結構有什麼缺點嗎?

  • 可能會增加額外的記錄掃描次數

#6)下面這個語句,在這兩個索引定義下分別是怎麼執行的?

select id,name,email from SUser where email='zhangssxyz@xxx.com';
登入後複製
登入後複製

index1(即email 整個字串的索引結構),執行順序

  • 從index1 索引樹找到滿足索引值是’zhangssxyz@xxx .com’的這條記錄,取得ID2 的值;

  • 回表查到主鍵值是ID2 的行,判斷email 的值是正確的,將這行記錄加入結果集;

  • 繼續在index索引樹的下一筆記錄,發現已經不滿足email='zhangssxyz@xxx.com’的條件了,循環結束。

這個過程中,只需要回主鍵索引取一次數據,所以系統認為只掃描了一行。

index2(即email(6) 索引結構),執行順序

  • 從index2 索引樹找到滿足索引值是’zhangs’的記錄,找到的第一個是ID1;

  • 到主鍵上查到主鍵值是ID1 的行,判斷出email 的值不是’zhangssxyz@xxx.com’,這行記錄丟棄;

  • 取index2 上剛剛查到的位置的下一筆記錄,發現仍然是’zhangs’,取出ID2,再到ID 索引上取整行然後判斷,這次值對了,將這行記錄加入結果集;

  • #重複上一步,直到在idxe2 上取到的值不是’zhangs’時,循環結束。

在這個過程中,要回主鍵索引取 4 次數據,也就是掃描了 4 行。

7)透過上面的對比,能得到什麼結論?

  • 使用前綴索引後,可能會導致查詢語句讀取資料的次數變多。

8)前綴索引真的一無是處嗎?

  • 如果我們定義的index2 不是email(6) 而是email(7),那滿足前綴’zhangss’的記錄只有一個,直接就查到ID2了,只掃描一行就結束了。

9)那麼使用前綴索引有哪些注意事項?

  • 長度選擇合理

10)當要給字串建立前綴索引時,我咋知道我該用多長的前綴索引呢?

  • 統計索引上有多少個不同的值來判斷要使用多長的前綴。

11)怎麼統計索引上有多少個不同的值?

select count(distinct email) as L from SUser;
登入後複製

12)拿到了索引對應的有多少個不同的值之後下一步該做什麼?

  • 依序選取不同長度的前綴來看這個值

    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 中,找出第一個不小於L * 95% 的值,說明透過這個索引可以找出百分之95以上的資料。

13)前綴索引對覆寫索引的影響為何?

下面這個 SQL 語句:

select id,email from SUser where email='zhangssxyz@xxx.com';
登入後複製

與前面範例中的 SQL 語句

select id,name,email from SUser where email='zhangssxyz@xxx.com';
登入後複製
登入後複製

相比,第一個語句只要求傳回 id 和 email 欄位。

  • 如果使用 index1(即 email 整個字串的索引結構)的話,查email的話就能得到ID,那就不用回表了,這個就是覆蓋索引。

  • 用 index2(即 email(6) 索引结构)的话,就不得不回到 ID 索引再去判断 email 字段的值。

14)那我把index2 的定义修改为 email(18) 的前缀索引不就行了?

  • 这个18是你自己定义的,系统不知道18这个长度是否已经大于我的email长度,所以它还是会回表去查一下验证。

总而言之:使用前缀索引就用不上覆盖索引对查询性能的优化了

针对类似于邮箱这样的字段,使用前缀索引可能会产生不错的效果。但是,遇到身份证这种前缀的区分度不够好的情况时,我们要怎么办呢?

  • 索引选取的要更长一些。

    • 但是所以越长的话,占的磁盘空间更大,相同的一页能放下的索引值就变少了,反而会影响查询效率。

16)如果我们能够确定业务需求里面只有按照身份证进行等值查询的需求,还有没有别的处理方法呢?

  • 既然正过来相同的多,那我就把它倒过来存。查询时候这样查

    select field_list from t where id_card = reverse('input_id_card_string');
    登入後複製

    使用 的时候用count(distinct) 方法去做个验证

  • 使用 hash 字段。在表上再创建一个整数字段,来保存身份证的校验码,同时在这个字段上创建索引。

    alter table t add id_card_crc int unsigned, add index(id_card_crc);
    登入後複製

    新记录插入时必须使用 crc32() 函数生成校验码,并填入新字段中。由于校验码可能存在冲突,也就是说两个不同的身份证号通过 crc32() 函数得到的结果可能是相同的,所以你的查询语句 where 部分要判断 id_card 的值是否精确相同。

    select field_list from t where id_card_crc=crc32('input_id_card_string') and id_card='input_id_card_string'
    登入後複製

    这样,索引的长度变成了 4 个字节(int类型),比原来小了很多

    17)使用倒序存储和使用 hash 字段这两种方法有什么异同点?

    • 相同点:都不支持范围查询

      • 倒序存储的字段上创建的索引是按照倒序字符串的方式排序的,已经没有办法利用索引方式查出身份证号码在[ID_X, ID_Y]的所有市民了。同样地,hash 字段的方式也只能支持等值查询。

    • 区别

      • 从占用的额外空间来看,倒序存储方式在主键索引上,不会消耗额外的存储空间,而 hash 字段方法需要增加一个字段。当然,倒序存储方式使用 4 个字节的前缀长度应该是不够的,如果再长一点,这个消耗跟额外这个 hash 字段也差不多抵消了。

      • 在 CPU 消耗方面,倒序方式每次写和读的时候,都需要额外调用一次 reverse 函数,而 hash 字段的方式需要额外调用一次 crc32() 函数。以仅考虑这两个函数的计算复杂度为前提,reverse 函数对 CPU 资源的额外消耗将较少。

      • 就查询性能而言,采用哈希字段方式的查询更具可靠性。虽然crc32算法不可避免地存在冲突的风险,但这种风险极其微小,因此我们可以认为查询时平均扫描行数接近于1。使用倒序存储方式仍然需要使用前缀索引来进行扫描,因此会增加扫描的行数。

    案例:如果你在维护一个学校的学生信息数据库,学生登录名的统一格式是”学号 @gmail.com", 而学号的规则是:十五位的数字,其中前三位是所在城市编号、第四到第六位是学校编号、第七位到第十位是入学年份、最后五位是顺序编号。

    学生必须输入正确的登录名和密码,方可继续使用系统。如果只考虑登录验证这个行为,你会如何为登录名设计索引?

    • 如果一个学校每年预计2万新生,50年才100万记录,如果直接使用全字段索引,可以节省多少存储空间?。除非遇到超大规模数据,否则不需要使用后两种方法,从而避免了开发转换和限制风险

    • 在实际操作中,只需对所有字段进行索引,一个学校的数据库数据量和查询负担不会变得很大。 如果单从优化数据表的角度: \1. 后缀@gmail可以单独一个字段来存,或者用业务代码来保证, \2. 城市编号和学校编号估计也不会变,也可以用业务代码来配置 \3. 然后直接存年份和顺序编号就行了,这个字段可以全字段索引

    以上是MySQL如何為字串欄位加索引的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1423
52
Laravel 教程
1321
25
PHP教程
1269
29
C# 教程
1249
24
laravel入門實例 laravel入門實例 Apr 18, 2025 pm 12:45 PM

Laravel 是一款 PHP 框架,用於輕鬆構建 Web 應用程序。它提供一系列強大的功能,包括:安裝: 使用 Composer 全局安裝 Laravel CLI,並在項目目錄中創建應用程序。路由: 在 routes/web.php 中定義 URL 和處理函數之間的關係。視圖: 在 resources/views 中創建視圖以呈現應用程序的界面。數據庫集成: 提供與 MySQL 等數據庫的開箱即用集成,並使用遷移來創建和修改表。模型和控制器: 模型表示數據庫實體,控制器處理 HTTP 請求。

MySQL和PhpMyAdmin:核心功能和功能 MySQL和PhpMyAdmin:核心功能和功能 Apr 22, 2025 am 12:12 AM

MySQL和phpMyAdmin是強大的數據庫管理工具。 1)MySQL用於創建數據庫和表、執行DML和SQL查詢。 2)phpMyAdmin提供直觀界面進行數據庫管理、表結構管理、數據操作和用戶權限管理。

MySQL與其他編程語言:一種比較 MySQL與其他編程語言:一種比較 Apr 19, 2025 am 12:22 AM

MySQL与其他编程语言相比,主要用于存储和管理数据,而其他语言如Python、Java、C 则用于逻辑处理和应用开发。MySQL以其高性能、可扩展性和跨平台支持著称,适合数据管理需求,而其他语言在各自领域如数据分析、企业应用和系统编程中各有优势。

解決數據庫連接問題:使用minii/db庫的實際案例 解決數據庫連接問題:使用minii/db庫的實際案例 Apr 18, 2025 am 07:09 AM

在開發一個小型應用時,我遇到了一個棘手的問題:需要快速集成一個輕量級的數據庫操作庫。嘗試了多個庫後,我發現它們要么功能過多,要么兼容性不佳。最終,我找到了minii/db,這是一個基於Yii2的簡化版本,完美地解決了我的問題。

laravel框架安裝方法 laravel框架安裝方法 Apr 18, 2025 pm 12:54 PM

文章摘要:本文提供了詳細分步說明,指導讀者如何輕鬆安裝 Laravel 框架。 Laravel 是一個功能強大的 PHP 框架,它 упростил 和加快了 web 應用程序的開發過程。本教程涵蓋了從系統要求到配置數據庫和設置路由等各個方面的安裝過程。通過遵循這些步驟,讀者可以快速高效地為他們的 Laravel 項目打下堅實的基礎。

解決MySQL模式問題:TheliaMySQLModesChecker模塊的使用體驗 解決MySQL模式問題:TheliaMySQLModesChecker模塊的使用體驗 Apr 18, 2025 am 08:42 AM

在使用Thelia開發電商網站時,我遇到了一個棘手的問題:MySQL模式設置不當,導致某些功能無法正常運行。經過一番探索,我找到了一個名為TheliaMySQLModesChecker的模塊,它能夠自動修復Thelia所需的MySQL模式,徹底解決了我的困擾。

MySQL:結構化數據和關係數據庫 MySQL:結構化數據和關係數據庫 Apr 18, 2025 am 12:22 AM

MySQL通過表結構和SQL查詢高效管理結構化數據,並通過外鍵實現表間關係。 1.創建表時定義數據格式和類型。 2.使用外鍵建立表間關係。 3.通過索引和查詢優化提高性能。 4.定期備份和監控數據庫確保數據安全和性能優化。

MySQL:解釋的關鍵功能和功能 MySQL:解釋的關鍵功能和功能 Apr 18, 2025 am 12:17 AM

MySQL是一個開源的關係型數據庫管理系統,廣泛應用於Web開發。它的關鍵特性包括:1.支持多種存儲引擎,如InnoDB和MyISAM,適用於不同場景;2.提供主從復制功能,利於負載均衡和數據備份;3.通過查詢優化和索引使用提高查詢效率。

See all articles