如何為MySQL中的JSON字段設置索引

背景

MySQL在2015年中發布的5.7.8版本中首次引入了JSON數據類型。自此,它成了一種逃離嚴格列定義的方式,可以存儲各種形狀和大小的JSON文檔,例如審計日志、配置信息、第三方數據包、用戶自定義字段等。

雖然MySQL提供了讀寫JSON數據的函數,但你很快會發現一個顯著的缺失:直接給JSON列建立索引的能力。

在其他數據庫中,直接索引JSON列的最佳方法通常是使用一種叫做廣義倒排索引(Generalized Inverted Index,簡稱GIN)的類型。然而,由于MySQL沒有提供GIN索引,我們無法直接對整個存儲的JSON文檔建立索引。不過不必擔心!MySQL確實為我們提供了一種間接索引存儲在JSON文檔中特定部分的方式。

根據所使用的MySQL版本,有兩個選項可以給JSON建立索引:

  • 如果使用MySQL 5.7,需要創建一個中間生成列(Generated Column)
  • 從MySQL 8.0.13開始,可以直接創建函數索引(Functional Index)

接下來,我們以一個示例表為例,該表用于記錄應用程序中的各種操作日志:

CREATE TABLE `activity_log` (`id` int(11) NOT NULL AUTO_INCREMENT,`properties` json NOT NULL,`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,PRIMARY KEY (`id`)
)

在該表的properties字段中插入如下結構的JSON文檔:

{"uuid": "e7af5df8-f477-4b9b-b074-ad72fe17f502","request": {"email": "little.bobby@tables.com","firstName": "Little","formType": "vehicle-inquiry","lastName": "Bobby","message": "Hello, can you tell me what the specs are for this vehicle?","postcode": "75016","townCity": "Dallas"}
}

在本例中,我們將嘗試索引request對象內的email鍵,這可以讓用戶快速找到由特定人員提交的表單。

方法一:通過“生成列”索引JSON

**生成列(Generated Column)**可以視為計算列、派生列或公式列。它的值是某個表達式的運算結果,而不是直接的數據輸入。表達式可以包含常量值、內置函數或對其他列的引用。表達式的結果必須是定量的(Scalar)且具有確定性(Deterministic)。

由于我們試圖索引properties列中的request.email字段,生成列將使用JSON的解引用(Unquoting Extraction)運算符來提取該值。

首先,運行一個SELECT語句來驗證表達式是否正確:

mysql> SELECT properties->>"$.request.email" FROM activity_log;
+--------------------------------+
| properties->>"$.request.email" |
+--------------------------------+
| little.bobby@tables.com        |
+--------------------------------+

符號->>是解引用運算符,它等價于如下的寫法:

mysql> SELECT JSON_UNQUOTE(JSON_EXTRACT(properties, "$.request.email"))->   FROM activity_log;
+-----------------------------------------------------------+
| JSON_UNQUOTE(JSON_EXTRACT(properties, "$.request.email")) |
+-----------------------------------------------------------+
| little.bobby@tables.com                                   |
+-----------------------------------------------------------+

上述兩種寫法,具體使用哪種方式可完全取決于個人偏好。

確認表達式的有效性和準確性后,我們使用它創建一個生成列

ALTER TABLE activity_log ADD COLUMN email VARCHAR(255)GENERATED ALWAYS as (properties->>"$.request.email");

這條ALTER語句的前半部分非常熟悉,添加了一個名為email的列,并將其定義為VARCHAR(255)類型。而后半部分聲明該列為生成列,并定義它始終等于表達式properties->>"$.request.email"的結果。

我們可以像其他列一樣查詢它,確認生成列已被成功添加:

mysql> SELECT id, email FROM activity_log;
+----+-------------------------+
| id | email                   |
+----+-------------------------+
|  1 | little.bobby@tables.com |
+----+-------------------------+

從結果可以看到,MySQL將動態維護這個列。如果我們更新了JSON數據,生成列的值也會隨之改變。

接下來,我們像其他普通列一樣為這生成列添加索引:

ALTER TABLE activity_log ADD INDEX email (email) USING BTREE;

現在已經成功為JSON中request.email鍵建立了索引。可以通過EXPLAIN驗證索引是否會被用于查詢:

mysql> EXPLAIN SELECT * FROM activity_log WHERE email = 'little.bobby@tables.com';

在這里插入圖片描述

結果顯示MySQL計劃使用email索引來滿足該查詢。

索引生成列與優化器(Optimizer)

MySQL的優化器是一個強大但神秘的組件。當我們給MySQL下達命令時,它理解的是我們想要什么,而不是我們明確指定如何實現。通常,MySQL會稍微改寫我們的查詢,這通常是一件好事。

對于生成列上的索引,優化器能“透過”不同的訪問模式以確保使用索引。例如,在以下查詢中,我們通過JSON提取運算符訪問數據,而不是直接使用生成的email列:

mysql> EXPLAIN SELECT * FROM activity_log->   WHERE properties->>"$.request.email" = 'little.bobby@tables.com';

結果可以看到優化器仍然使用了email索引。哪怕使用長寫的表達式,也可以看到優化器仍然“穿透”表達式并利用了索引,甚至可以通過SHOW WARNINGS查看優化器改寫后的查詢:

mysql> SHOW WARNINGS;

顯示結果表明查詢被改寫為直接參考了索引的列。

方法二:函數索引(Functional Index)

從MySQL 8.0.13開始,可以跳過創建生成列的中間步驟,直接創建表達式索引(Function Index)。例如:

ALTER TABLE activity_logADD INDEX email ((properties->>"$.request.email")) USING BTREE;

然而,當你嘗試運行上述語句時會遇到錯誤:

ERROR: Cannot create a functional index on an expression that returns a BLOB or TEXT. Please consider using CAST.

這是因為MySQL自動推斷JSON解引用操作返回LONGTEXT類型,而無法對其直接建立索引。可通過CAST將值轉化為MySQL可索引的數據類型:

ALTER TABLE activity_logADD INDEX email ((CAST(properties->>"$.request.email" AS CHAR(255)))) USING BTREE;

此外還需要解決字符集不匹配的問題,需要顯式設置排序規則為utf8mb4_bin

ALTER TABLE activity_logADD INDEX email ((CAST(properties->>"$.request.email" AS CHAR(255)) COLLATE utf8mb4_bin)) USING BTREE;

運行EXPLAIN后可以確認函數索引已成功被使用。

總結

盡管MySQL無法直接對JSON列建立索引,但通過生成列和函數索引的方式間接索引特定字段能夠滿足絕大多數場景。同時這種方式不僅適用于JSON,還適用于其它復雜或難以索引的模式。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/96595.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/96595.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/96595.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【學習日記】

1.上午看了會面經,八股,很多看不懂1.5排查本地mysql服務啟動問題2.刷了兩道題翻轉二叉樹的Dfs和bfs遞歸方法,看了幾分鐘看懂了,一開始刷題,沒有這種感覺,可能思維上升了3.下午做了會ppt4.看了ssm的一個gith…

本地大模型部署指南-Ollama與HuggingFace對比

在本地部署大模型時,用 Ollama 和 Hugging Face (HF) 確實有很大區別,涉及系統、硬件、訓練、推理方式,以及能否查看模型源代碼。下面我分幾個維度說明: 系統和安裝 Ollama 定位是「開箱即用」的本地大模型運行環境。 自帶運行時&…

河北周邊有哪些比較靠譜的智算中心?

河北省通過算力普惠、綠色能源、數據開放、金融支持四大支柱政策,推動智算中心高質量發展。河北及周邊地區的智算中心已形成高可靠性、先進技術和戰略協同的布局。那么,河北周邊有哪些比較靠譜的智算中心?一、河北周邊智算中心盤點?1、尚航懷…

電動汽車充電標準之 — 國標 GB/T 18487《電動汽車傳導充電系統》 簡介

GB/T 18487 的全稱是 《電動汽車傳導充電系統》 ,它是中國電動汽車充電領域最基礎、最核心的國家標準之一。該標準規定了電動汽車傳導充電系統的通用要求、通信協議、安全要求等,是整個中國充電基礎設施建設的基石。 與您之前了解的IEC 61851類似&#x…

溫濕度傳感器如何守護工業制造?

在工業制造、農業養殖、倉儲物流乃至文物保護等領域,環境溫濕度的精確監測是保障品質與安全的關鍵。溫濕度傳感器作為無聲的守護者,如何通過穩定可靠的數據采集,為現代工業生產的精細化與智能化管理提供堅實基礎?本文將深入探討其…

破壁·融合·共贏:杭州大成慧谷基金與涉海科技混改項目公司正式啟航!

2025 年 7 月 15 日,一家融合國企基金實力與民企創新活力的混合所有制項目公司正式誕生——由杭州大成慧谷股權投資基金管理有限公司與山東涉海海洋生物科技有限公司共同出資設立的武創慧聚創芯科學技術(上海)有限公司,當日完成法律合規手續。此前,上海武創大智高新技術集團副總…

洛谷 P1271 【深基9.例1】選舉學生會-普及-

P1271 【深基9.例1】選舉學生會 題目描述 學校正在選舉學生會成員,有 nnn(1≤n≤9991 \le n\le 9991≤n≤999)名候選人,每名候選人編號分別從 111 到 nnn,現在收集到了 mmm(1≤m≤20000001 \le m \le 20000…

【AI】AI 評測入門(二):Prompt 迭代實戰從“能跑通”到“能落地”

“Prompt 不是寫出來的,是測出來的。” ——這是我迭代 5 個版本后,最深的體悟。 上一篇《AI 評測入門(一):先搞懂你的數據集)》,我們講了標簽體系、自測集、評測集、Langfuse 數據結構化——那是 AI 評測的…

【好靶場】SQLMap靶場攻防繞過 (一)

0x00 前言 最近遇到很多在做基礎靶場的小伙伴們都在SQLMap一把索,那么所幸搞一個SQLMap繞過的靶場。 我們是好靶場,一個立志于讓所有學習安全的同學用上好靶場的團隊。 https://github.com/haobachang-1/haobachangBlog/ https://github.com/haobach…

DeepSeek輔助編寫的利用quick_xml把xml轉為csv的rust程序

提示詞請用rust quickxml庫實現讀取xml的row和c標簽信息,并輸出到csv格式,要求是:數值型c,輸出標簽的內容,字符串型c(t “inlineStr”),輸出的內容,row的r屬性表是行號,c的r屬性是字…

logback-spring.xml文件說明

項目里剛好用到&#xff0c;用豆包生成以下說明&#xff0c;此處作為記錄。以下是一個 logback-spring.xml 配置文件示例&#xff0c;結合了 Spring Boot 特性&#xff0c;支持環境區分、日志滾動和不同級別日志輸出&#xff0c;并包含詳細注釋&#xff1a;<?xml version&q…

專題:2025社交媒體營銷與電商融合趨勢報告:抖音、小紅書、短劇、直播全拆解|附210+份報告PDF、數據儀表盤匯總下載

原文鏈接&#xff1a;https://tecdat.cn/?p43853 原文出處&#xff1a;拓端抖音號拓端tecdat 3年前&#xff0c;電商還停留在“貨架擺貨、用戶搜關鍵詞下單”的傳統模式&#xff0c;社交媒體只是品牌“打知名度”的輔助工具&#xff1b;如今&#xff0c;用戶刷抖音直播能直接下…

大模型API密鑰生成規則分析

大模型API密鑰生成規則分析 一、核心生成原則與安全基礎 1.1 密碼學安全隨機數生成 大模型API密鑰的核心安全基礎在于高熵值隨機數生成,需滿足以下技術標準: 熵值要求:至少128位(16字節),推薦256位(32字節),通過密碼學安全偽隨機數生成器(CSPRNG)實現 生成算法:…

太陽光度計在光伏電站的用途

太陽光度計在光伏電站中具有多重關鍵用途&#xff0c;能夠為電站的規劃、運行、維護及能效提升提供科學依據。以下是其具體應用場景及價值分析&#xff1a;1. 太陽能資源評估與電站選址優化核心功能&#xff1a;太陽光度計通過測量直接太陽輻射&#xff08;DNI&#xff09;、散…

ArkTS(方舟 TypeScript)全面介紹:鴻蒙生態的核心編程語言

一、引言 隨著鴻蒙(HarmonyOS)的快速演進,開發者生態成為支撐其發展的關鍵因素。無論是手機、平板、智能穿戴,還是車機、IoT 設備,鴻蒙都希望通過“一次開發,多端部署”的理念,讓開發者能夠更高效地構建應用。 為了實現這一目標,華為推出了 ArkTS(方舟 TypeScript)…

領碼方案|Linux 下 PLT → PDF 轉換服務超級完整版:異步、權限、進度(一氣呵成)

本教程給出可直接落地的 Linux 環境下 PLT→PDF 轉換微服務&#xff0c;全鏈路涵蓋&#xff1a;同步/異步模式、JWTRBAC項目域權限、任務狀態與進度、PDF 水印與審計、可觀測性與彈性伸縮&#xff1b;技術棧為 Spring Boot gpcl6&#xff08;GhostPCL&#xff09; Redis S3/O…

基于51單片機的LCD12864萬年歷時鐘

目錄 具體實現功能 設計介紹 資料內容 全部內容 資料獲取 具體實現功能 具體功能&#xff1a; &#xff08;1&#xff09;LCD12864實時顯示當前時間&#xff08;年月日時分秒星期&#xff09;及溫度值&#xff1b; &#xff08;2&#xff09;四個按鍵可調整當前時間值&…

【C++】string類--常見接口及其模擬實現

目錄 1. 遍歷 1.1. 下標operator[ ] 1.2. c_str 1.3. 迭代器 1.4. 范圍for 2. 增 2.1. push_back 2.2. 重載&#xff08;char ch&#xff09; 2.3. appand 2.4. 重載&#xff08;char* ch&#xff09; 2.5. insert&#xff08;任意位置插入&#xff09; 2.5.1. 任意…

SCADA 云化部署核心:WebSocket 協議實現毫秒級遠程控制

在浙江某智慧水廠的中控室里&#xff0c;曾發生過一次驚險的遠程控制失誤&#xff1a;運維人員通過傳統 SCADA 系統&#xff08;工業控制系統的 “大腦”&#xff09;遠程調節水泵轉速&#xff0c;指令發出后&#xff0c;屏幕上卻遲遲沒有反饋 —— 等水泵轉速最終變化時&#…

大數據電商流量分析項目實戰:Day1-2 補充 軟件安裝和Zookeeper

?博客主頁&#xff1a; https://blog.csdn.net/m0_63815035?typeblog &#x1f497;《博客內容》&#xff1a;大數據、Java、測試開發、Python、Android、Go、Node、Android前端小程序等相關領域知識 &#x1f4e2;博客專欄&#xff1a; https://blog.csdn.net/m0_63815035/…