從“存得對”到“存得準”:MySQL 數據類型與約束全景指南

目錄

一、為什么需要數據類型與約束?

二、MySQL 數據類型全覽

1. 數值類型:精確 VS 近似

2. 日期時間類型:別讓“0000-00-00”出現

3. 字符串類型:CHAR、VARCHAR、TEXT、BLOB

4. JSON 類型:文檔與關系共舞

5. 空間類型:GIS 場景

6. 二進制與位類型

三、約束:給數據裝上“安檢門”

1. 列級約束:NOT NULL、DEFAULT、UNIQUE、CHECK

2. 主鍵與復合主鍵

3. 外鍵:一把雙刃劍

4. 表級 CHECK 與觸發器

5. 視圖與權限:最后一道軟性約束

四、聯動設計:把類型與約束串成故事

1. 用戶表

2. 訂單表

3. 支付表

4. 索引與性能

五、最佳實踐 5 條

六、結語


一、為什么需要數據類型與約束?

想象你在咖啡館點單:
“我要一杯拿鐵,中杯,加一份濃縮,半糖,少冰。”
如果服務員只在本子上寫“拿鐵”,結果可能端來超大杯、全糖、冰多到溢出。
數據庫同理:字段若不聲明“多大”“什么格式”“能否為空”,就會像“拿鐵”一樣失控——數字被截斷、日期變 0000-00-00、字符串亂碼、金額出現負值……
數據類型解決“存得對”,約束保證“存得準”。二者共同構成 MySQL 的第一道防線,也是性能與可維護性的根基。

二、MySQL 數據類型全覽

1. 數值類型:精確 VS 近似

大類典型字節范圍(有符號)場景
整數TINYINT1-128~127性別、布爾
整數INT4-21 億~21 億主鍵、計數器
大整數BIGINT8很大雪花 ID
定點DECIMAL(M,D)變長精確小數金額
浮點FLOAT/DOUBLE4/8近似值溫度、GPS

陷阱與建議:

  • 金額永遠用 DECIMAL,不要用 DOUBLE。DOUBLE 的二進制浮點誤差會讓 0.1+0.2≠0.3。

  • 主鍵自增別用 BIGINT(20)“嚇唬”自己,除非預估 9.22e18 行,否則 INT 足夠。

  • UNSIGNED 讓上限翻倍,但 BIGINT UNSIGNED 與 Java long 互轉時會溢出,需在 ORM 層注意。

示例:

CREATE TABLE goods (id        BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,price     DECIMAL(10,2) NOT NULL,stock     INT UNSIGNED DEFAULT 0
);

2. 日期時間類型:別讓“0000-00-00”出現

類型字節范圍精確度備注
DATE31000-01-01~9999-12-31生日
DATETIME8同上默認無時區
DATETIME(fsp)8+小數同上微秒MySQL 5.6+
TIMESTAMP41970-2038自動時區轉換
TIME3-838:59:59~838:59:59時長
YEAR11901-2155幾乎不用

陷阱:

  • 舊版本 MySQL 允許 0000-00-00,但 JDBC、Python 驅動會拋異常;務必 sql_mode=NO_ZERO_DATE

  • TIMESTAMP 受時區影響,跨地域系統用 DATETIME+fsp 更穩。

  • 存儲毫秒級時間戳可直接用 BIGINT 存 Unix 毫秒,避免 DATETIME 精度不夠或 TIMESTAMP 2038 問題。

示例:

CREATE TABLE event_log (id        BIGINT PRIMARY KEY,happen_at DATETIME(3) NOT NULL,INDEX idx_happen (happen_at)
);

3. 字符串類型:CHAR、VARCHAR、TEXT、BLOB

  • CHAR(n) 定長,最大 255,尾部空格自動截斷;適合短且等長碼值,如國家代碼 CHAR(2)

  • VARCHAR(n) 變長,最大 65535 字節,受行大小 65535 限制;utf8mb4 下一個字符 4 字節,所以 VARCHAR(16383) 是極限。

  • TEXT 家族(TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT)存大文本,不能設默認值,不能完整索引(需前綴索引)。

  • BLOB 家族存二進制,如圖片、PDF;同樣不能設默認值,讀寫會走磁盤臨時文件,慎用。

陷阱:

  • VARCHAR(255) 不等于 255 字符,而是 255 字節;utf8mb4 下最多 63 個漢字。

  • 用 TEXT 存 JSON 不如直接用 JSON 類型(見下)。

  • 大字段會觸發“行溢出”,InnoDB 把值存到頁外,隨機 IO 增加。

示例:

CREATE TABLE article (id      BIGINT PRIMARY KEY,title   VARCHAR(200) NOT NULL,body    MEDIUMTEXT,cover   LONGBLOB
) CHARSET=utf8mb4;

4. JSON 類型:文檔與關系共舞

MySQL 5.7+ 原生 JSON,二進制存儲、可部分更新。支持函數 ->->>JSON_EXTRACT()JSON_SET()
優點:schema-less,適合動態字段。缺點:無法直接建外鍵、無法默認值。
示例:

CREATE TABLE user_ext (user_id BIGINT PRIMARY KEY,profile JSON,CHECK (JSON_VALID(profile))
);-- 查詢
SELECT profile->>'$.nickname' AS nick
FROM user_ext
WHERE JSON_CONTAINS(profile->'$.tags', '"vip"');

5. 空間類型:GIS 場景

  • GEOMETRY、POINT、LINESTRING、POLYGON……

  • 需表引擎 InnoDB 或 MyISAM,建 SPATIAL INDEX。

  • 8.0 引入 SRID 強制坐標系,避免“經緯度顛倒”。

示例:

CREATE TABLE shop (id   BIGINT PRIMARY KEY,loc  POINT NOT NULL SRID 4326,SPATIAL INDEX idx_loc (loc)
);

6. 二進制與位類型

  • BINARY/VARBINARY:與 CHAR/VARCHAR 類似,但存字節而非字符,適合存哈希。

  • BIT:最大 64 位,存布爾標志位,省空間但可讀性差。

  • ENUM/SET:背后用 1~8 字節存位圖,可節省空間,但遷移成本高,不建議濫用。

三、約束:給數據裝上“安檢門”

1. 列級約束:NOT NULL、DEFAULT、UNIQUE、CHECK

  • NOT NULL:拒絕 NULL;NULL 與任何值比較都未知,導致索引失效。

  • DEFAULT:顯式優于隱式;DEFAULT CURRENT_TIMESTAMP 記錄創建時間。

  • UNIQUE:允許 NULL,但 NULL≠NULL,因此可出現多條 NULL;8.0.13 前不能有重復 NULL。

  • CHECK:8.0.16 原生支持,之前僅解析忽略;可寫表達式 CHECK (age BETWEEN 0 AND 150)

示例:

CREATE TABLE member (id     BIGINT PRIMARY KEY,email  VARCHAR(255) NOT NULL UNIQUE,age    TINYINT CHECK (age BETWEEN 0 AND 150),status ENUM('NEW','VIP','BAN') DEFAULT 'NEW'
);

2. 主鍵與復合主鍵

  • 主鍵 = NOT NULL + UNIQUE;InnoDB 聚簇索引,整張表物理順序按主鍵排序。

  • 業務主鍵 vs 代理主鍵:自增 BIGINT 簡單,但分布式場景用雪花 ID、UUID;后者無序會導致頁分裂。

  • 復合主鍵 (tenant_id, id) 可做分庫分表“聯合主鍵”,但所有二級索引都需回表兩次。

3. 外鍵:一把雙刃劍

CREATE TABLE orders (id      BIGINT PRIMARY KEY,user_id BIGINT NOT NULL,FOREIGN KEY (user_id) REFERENCES user(id)ON UPDATE CASCADEON DELETE RESTRICT
);

優點:保證引用完整性;缺點:高并發寫入時級聯更新/刪除會鎖多表,互聯網大廠常關閉外鍵,靠業務層保證。

4. 表級 CHECK 與觸發器

  • 如果 CHECK 表達式復雜(如跨列、跨行),可用 BEFORE INSERT 觸發器。

  • 觸發器可寫業務邏輯,但隱藏、難調試,盡量收斂到“數據校驗”而非“業務流程”。

示例:

DELIMITER $$
CREATE TRIGGER trg_order_amount
BEFORE INSERT ON orders
FOR EACH ROW
BEGINIF NEW.amount <= 0 THENSIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'amount must be positive';END IF;
END$$
DELIMITER ;

5. 視圖與權限:最后一道軟性約束

  • 通過只讀視圖屏蔽危險列;

  • DEFINERSQL SECURITY INVOKER 做行級安全。

四、聯動設計:把類型與約束串成故事

場景:設計“用戶-訂單-支付”核心表,要求:

  • 用戶手機號唯一;

  • 訂單金額必須大于 0;

  • 支付記錄必須與訂單同幣種;

  • 支持軟刪除。

1. 用戶表

CREATE TABLE user (id        BIGINT PRIMARY KEY,phone     CHAR(11) NOT NULL UNIQUE,nickname  VARCHAR(50),deleted   TINYINT(1) DEFAULT 0,created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) CHARSET=utf8mb4;

2. 訂單表

CREATE TABLE orders (id        BIGINT PRIMARY KEY,user_id   BIGINT NOT NULL,amount    DECIMAL(10,2) NOT NULL CHECK (amount > 0),currency  CHAR(3) DEFAULT 'CNY',status    ENUM('PENDING','PAID','CLOSED') DEFAULT 'PENDING',deleted   TINYINT(1) DEFAULT 0,FOREIGN KEY (user_id) REFERENCES user(id)ON DELETE RESTRICTON UPDATE CASCADE
);

3. 支付表

CREATE TABLE payment (id        BIGINT PRIMARY KEY,order_id  BIGINT NOT NULL,currency  CHAR(3) NOT NULL,pay_amount DECIMAL(10,2) NOT NULL CHECK (pay_amount > 0),paid_at   DATETIME DEFAULT CURRENT_TIMESTAMP,FOREIGN KEY (order_id) REFERENCES orders(id)ON DELETE RESTRICT,CONSTRAINT chk_currency_matchCHECK (currency = (SELECT currency FROM orders WHERE id = order_id))
);

注意:MySQL 8.0.16+ 才支持子查詢 CHECK;低版本需觸發器實現。

4. 索引與性能

  • 外鍵會自動創建索引,但 deleted 列需手動加聯合索引 (deleted, status) 以便軟刪除列表查詢。

  • DECIMAL 精確字段可用“整數分”代替:存分為 INT,避免浮點運算。

五、最佳實踐 5 條

  1. 先選類型,再加約束:類型決定存儲空間與運算方式,約束只是“護欄”。

  2. 金額用 DECIMAL(10,2) + CHECK>0;時間用 DATETIME(3) + DEFAULT CURRENT_TIMESTAMP(3)。

  3. 枚舉值用 TINYINT 或 VARCHAR 存代碼,留擴展空間;ENUM 僅用于非常穩定的狀態機。

  4. 外鍵在 OLTP 關閉,在 OLAP 打開;或只在測試環境打開做 CI。

  5. 上線前跑 pt-oscgh-ost 做無鎖變更,防止加約束導致表鎖。

六、結語

數據類型與約束是 MySQL 的地基。
類型選錯,查詢再花哨也如沙上建塔;約束缺失,業務再健壯也靠運氣生存。
愿你在每一次 CREATE TABLE 時,都能像挑剔的點單顧客,把“中杯、半糖、少冰”說得清清楚楚,讓數據庫端出的每一杯“數據拿鐵”都剛剛好。

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

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

相關文章

Effective C++ 條款42:了解 typename 的雙重含義

Effective C 條款42&#xff1a;了解typename的雙重含義 核心思想&#xff1a;在模板聲明中&#xff0c;typename和class可互換使用&#xff0c;但在模板內部&#xff0c;typename必須用于顯式指明嵌套從屬類型名稱&#xff08;nested dependent type name&#xff09;&#xf…

ENCOPIM, S.L. 參展 AUTO TECH China 2025 廣州國際汽車技術展覽會

ENCOPIM, S.L. 參展 AUTO TECH China 2025 廣州國際汽車技術展覽會2025年11月21-24日中國進出口商品交易會展館D區(廣州)AUTO TECH China 2025同期&#xff1a;第二十三屆廣州車展即將盛大開幕展商推薦ENCOPIM, S.L.展位號&#xff1a;3916企業簡介&#xff1a;ENCOPIM, S.L.于…

30 HTB Soccer 機器 - 容易

主要知識點 第一階段&#xff1a;偵查 nmap nmap快速掃描&#xff1a; oxdfhacky$ nmap -p- --min-rate 10000 10.10.11.194 Starting Nmap 7.80 ( https://nmap.org ) at 2023-06-04 13:32 EDT Nmap scan report for 10.10.11.194 Host is up (0.093s latency). Not shown:…

阿里云機器翻譯接口SDK-RAM權限配置

用戶授權翻譯權限在數字化時代&#xff0c;短信作為企業與用戶溝通的重要橋梁&#xff0c;其高效、可靠的送達直接影響業務轉化與用戶體驗。SDK&#xff08;軟件開發工具包&#xff09;的出現極大簡化了短信功能的集成過程&#xff0c;讓開發者能夠快速在應用中嵌入短信驗證、通…

ESXI 6.7服務器時間錯亂問題

1. 設置ESXI服務器&#xff1a;在此主機上手動配置日期和時間管理-服務-ntpd-鼠標右鍵-策略-手動啟動和停止&#xff0c;狀態已停止管理-系統-時間和日期-編輯設置-檢查是否選擇了【在此主機上手動配置日期和時間】ntp服務狀態已停止ntp服務器已停止2. 停止所有虛擬機自動更新時…

CV 醫學影像分類、分割、目標檢測,之【皮膚病分類】項目拆解

CV 醫學影像分類、分割、目標檢測&#xff0c;之【皮膚病分類】項目拆解第1-12行&#xff1a;導入庫第14-17行&#xff1a;讀取標簽文件第19-21行&#xff1a;獲取疾病名稱第23-26行&#xff1a;獲取圖片名列表第28-35行&#xff1a;篩選有標簽的圖片第38-43行&#xff1a;提取…

【JavaEE】多線程 -- 線程狀態

目錄六大狀態舉例說明六大狀態 New 新建狀態&#xff1a;線程還沒出創建&#xff0c;只有Thread 實例化的對象&#xff0c;調用start 方法之前的狀態。Runnable 運行狀態&#xff1a;被系統調度后&#xff0c;CPU 正在執行的&#xff0c;Ready 就緒態&#xff0c;系統調度&…

網絡流初步

網絡流初步 文章目錄網絡流初步概念介紹最大流費用流概念介紹 網絡流不同之處在于它的本質圖論&#xff0c;但是把圖論的某些概念換了一個說法而已&#xff0c;初步只要了解網絡流的各個概念就可以明白的很快。 下述概念是本人自己定義的&#xff0c;對于網絡流的題目做的還不…

[系統架構設計師]系統架構基礎知識(一)

[系統架構設計師]系統架構基礎知識&#xff08;一&#xff09; 一.計算機系統基礎知識 1.計算機系統概述 硬件軟件及網絡組成的系統 2.計算機硬件基礎知識 馮 諾依曼結構&#xff1a;運算器&#xff0c;控制器&#xff0c;存儲器&#xff0c;輸入設備&#xff0c;輸出設備 專用…

深入解析Java代理模式:靈活控制對象訪問的核心技術

在日常開發中&#xff0c;我們常遇到這樣的場景&#xff1a;需要控制對象訪問權限、優化高成本操作&#xff0c;或給方法添加額外功能&#xff08;如日志、事務&#xff09;。代理模式&#xff08;Proxy Pattern&#xff09; 正是解決這類問題的金鑰匙。作為結構型設計模式的代…

【學習筆記】Java并發編程的藝術——第9章 Java中的線程池

第9章 Java中的線程池 線程池優勢&#xff1a; ①減少資源消耗 ②提高響應速度 ③統一管理 9.1 線程池的實現原理 當任務來后 ①判斷核心線程池是否已滿&#xff0c;若未滿&#xff0c;創建一個核心線程來執行任務 ②若無空閑核心線程且核心線程已滿&#xff0c;則將任務放入任…

Mybatis學習筆記(九)

常見問題與解決方案 簡要描述&#xff1a;總結MyBatis-Plus開發過程中常見的問題、錯誤及其解決方案&#xff0c;幫助開發者快速定位和解決問題。 核心概念&#xff1a; 常見錯誤&#xff1a;開發中經常遇到的錯誤類型性能問題&#xff1a;性能相關問題的排查和解決配置問題&am…

數據類型 list

一、介紹類似于數組&#xff0c;順序表&#xff0c;deque結構圖特點&#xff1a;元素有序&#xff0c;元素允許重復由于頭尾高效插入刪除&#xff0c;可以模擬棧&#xff0c;隊列二、常見 list 命令1、lpush key elem [elem ...]頭插元素&#xff0c;返回值列表長度2、lrange k…

pyqt5無法顯示opencv繪制文本和掩碼信息

背景&#xff1a;pyqt5無法顯示opencv繪制的標簽和mask&#xff1b;我們在使用YOLO做實例分割做推理時&#xff0c;會使用opencv做后處理結果繪制&#xff08;含標簽繪制和掩碼繪制&#xff09;&#xff1b;結果opencv繪制的解碼卻無法在pyqt的解碼上面顯示。pyqt轉換代碼如下&…

如何生成嚴格遞增的分布式id?

本文字數&#xff1a;2604字預計閱讀時間&#xff1a;15分鐘01引言在現有分布式系統中&#xff0c;面對增長迅速的業務數據&#xff0c;id生成一直是非常重要的一環。而分布式系統的id生成方案需要滿足幾個重要特性&#xff1a;容錯高可用、高性能高并發、全局唯一。02技術背景…

【LeetCode】二叉樹相關算法題

目錄1、二叉樹介紹【1】核心概念【2】關鍵特性2、算法題【1】二叉樹的前序遍歷【2】二叉樹的后序遍歷1、二叉樹介紹 【1】核心概念 結構含義節點結構二叉樹由節點組成&#xff0c; 每個節點包含一個數據元素和最多兩個子節點&#xff1a;左子節點和右子節點根節點樹的頂部節點…

Vulnhub Deathnote靶機復現攻略

一、靶機安裝 下載地址&#xff1a;https://download.vulnhub.com/deathnote/Deathnote.ova 下載好后使用VB打開&#xff0c;配置如下 二、主機發現 使用相同連接方式的kali進行后續操作(172.16.2.7)根據mac地址進行確認。 nmap -sn 172.16.2.1/24 三、端口掃描 端口開放了…

DevEco Studio 6.0.0 元服務頁面跳轉失敗

背景&#xff0c;我使用最新的編輯器DevEco Studio 6.0.0&#xff0c;編寫一個元服務&#xff0c;發現使用跳轉頁面的時候失敗了&#xff01;然后查看官方文檔&#xff0c;兩種方式都測試了&#xff0c;發現都不行。 方法1&#xff1a;Navigation路由跳轉無效&#xff0c;見官方…

docker重啟或系統重啟后harbor自動啟動

docker重啟或系統重啟后harbor自動啟動docker重啟或系統重啟后harbor自動啟動方法 1&#xff1a;在 docker-compose.yml 中配置重啟策略&#xff08;推薦&#xff09;方法 2&#xff1a;創建 Systemd 服務&#xff08;更可靠&#xff09;方法 3&#xff1a;使用 Docker 的 Rest…

OpenZeppelin Contracts 架構分層分析

OpenZeppelin Contracts 是一個面向以太坊&#xff08;及兼容 EVM 的區塊鏈&#xff09;生態系統的??模塊化、安全性優先、標準兼容的智能合約庫??。其內部代碼按照功能職責與抽象層級&#xff0c;可系統性地劃分為多個邏輯層次。理解這些層次及其依賴關系&#xff0c;對于…