MySQL之分區功能

序言

隨著業務發展,我們維護的項目數據庫中的數據可能會越來越大,那么單張表的數據變多后,接口查詢效率可能會變慢,那我們就直接照抄大廠常見的分庫分表嗎?—— 當然不是的,分庫分表不是萬能的。

分庫分表會大大提高系統的復雜度,并且里面可能會踩不少坑:

  • 分布式事務:比如進行了數據庫表垂直拆分,那可能會涉及到分布式事務,可能就需要考慮2PC、3PC、Seata TCC、本地事務表等方案;
  • 分布式ID:單表可能搞個自增主鍵就完事了,但是如果進行了分庫分表,比如對數據庫表進行了水平拆分,那你后續數據量變更多的時候,你需要再進行擴容,簡單的自增主鍵可能會導致多張數據庫表的主鍵重復且不唯一,那就得用到分布式Id,比如雪花算法(還需要考慮時間回撥、機器號管理問題)或美團的Leaf,相當于你可能需要專門搞個“發號器”服務;
  • 分片查詢:假設還是對數據庫表進行了水平拆分,原來執行一句select * from table where age > 25的SQL,現在需要跑遍所有分片,然后需要考慮把所有結果放在內存拼起來會不會讓內存爆炸;
  • 數據備份/擴容:水平分庫或者垂直分庫后,數據庫多了,運維時備份策略復雜到要畫思維導圖,擴容就像給高速行駛的汽車換輪胎——稍有不慎全村吃席;

真實案例:電商搞大促,本來分庫分表是為了抗住流量,結果庫存扣減因為跨庫事務超時,30%訂單直接失敗。CTO 當場血壓飆升:“這特么還不如不分!”

解決方案

    1. 索引優化:給數據庫穿雙跑鞋
      別上來就搞分庫分表,先看看你的索引是不是像老太太的裹腳布——又臭又長?
      殺手锏:用EXPLAIN命令看SQL執行計劃,把那些全表掃描(ALL)、臨時表(Using temporary)的查詢揪出來打;
      口訣:聯合索引遵循“最左匹配”,別建一堆單列索引占著茅坑不拉屎;
    1. 冷熱分離:給數據分個「退休區」
      3 年前的訂單還天天查?不如把陳年老數據歸檔到history_orders表;
      野路子:直接CREATE TABLE archive_table AS SELECT * FROM orders Where create_time < '2025-01-01'(記得加索引)
      好處:主表瘦身成功,查詢速度飛起;
    1. 分區表:把大桌子切成抽屜
      不用改代碼!MySQL 自帶分區功能,按月分、按 ID 分隨你便;
    1. 讀寫分離:讓小弟們干活
      主庫專心寫數據,搞 10 個從庫輪著查,用ShardingSphere這類工具自動分流;
      注意:從庫可能有延遲,重要操作(比如支付成功頁)還是得查主庫
    1. 垂直拆分:把胖子表扒層皮
      把大字段(比如商品詳情、用戶頭像)單獨存個表,主表只留核心字段
      栗子:用戶表拆成 (存 ID、姓名)和 (存地址、簡介),減 少單行數據體積
    1. 氪金大法:加錢上 SSD!
      別笑!很多公司用機械硬盤跑數據庫,換 SSD 直接性能翻 10 倍
      調參秘籍:
      innodb_buffer_pool_size調到機器內存的 70%(別讓數據庫餓著)
      innodb_flush_log_at_trx_commit=2適當犧牲點安全性換速度
    1. 找外援:NoSQL 來幫忙
      搜索交給 ES:商品模糊查詢別折騰數據庫,Elasticsearch 專治各種不服;
      緩存懟臉上:用 Redis 存庫存、熱門商品,讀請求直接不碰數據庫
      日志存 Mongo:用戶操作日志這種大 JSON,往 MongoDB一扔,省心省力;

什么情況必須分庫分表?

  • 數據量打不住:單表超過 5000 萬行,眼瞅著要破億(比如微信的消息表);
  • 錢砸不動了:SSD 買頂配、內存加到 512G 還是卡成狗;
  • 業務逼到墻角:每秒上萬筆交易,不拆分明天就宕機;

分庫分表兩大流派:

  • 垂直拆分:用戶表、訂單表、商品表各占一個庫,適合業務復雜的中臺系統;
  • 水平拆分:
    • 按用戶 ID 取模:簡單粗暴,但擴容得重新分片;
    • 一致性哈希:擴容時只要遷移部分數據,互聯網公司最愛;
    • 按時間分片:適合日志類數據,直接按月分庫;

分區表

上面的幾種解決方案大多人多多少少都見過了,然后我們來看看分區表,下面就實戰的看看分區表怎么玩?

由于MySQL天然支持分區操作,我們直接看看官網:mysql_doc_alter-table-partition-operations

先看我們展示的非分區表,表結構如下,
在這里插入圖片描述
數據如下圖所示,id為主鍵,
在這里插入圖片描述
這里只是拿之前測試用的表做展示,表結構可以更加簡化,這張表我們可以通過Hash主鍵id作為分區鍵,假設我們劃分8個分區,執行下面的SQL指令,

ALTER TABLE `USER`PARTITION BY HASH(id)PARTITIONS 8;

執行結果如下圖,可以看到Partitioning Hash算法執行完后數據分布相對均勻,其實是因為在MySQL 8.4版本支持的線性Hash算法
在這里插入圖片描述
執行下面SQL命令,我們可以查看當前數據庫表的分區情況

SELECT TABLE_SCHEMA, TABLE_NAME, PARTITION_NAME, PARTITION_METHOD, PARTITION_EXPRESSION, PARTITION_DESCRIPTION
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_SCHEMA = 'testdemo' AND TABLE_NAME = 'USER';

結果如下圖所示,數據庫、表名、分區名、分區方法等一目了然,
在這里插入圖片描述
理論上,執行ALTER TABLE USER DROP PARTITION p0,p1,p2,p3,p4,p5,p6,p7;是可以刪除分區的,但是由于DROP PARTITION語句只能用于刪除范圍(RANGE)分區或列表(LIST)分區中的分區。這兩種分區類型允許你基于連續的值范圍或特定的值列表來組織數據。哈希(HASH)分區和鍵(KEY)分區是基于算法而非明確的值范圍或列表進行分區的,因此不支持使用 DROP PARTITION 語句。
在這里插入圖片描述

針對Hash分區和Key分區,我們可以執行下面命令還原成1個分區,但本質上和初始情況還是有一點差別,初始情況是沒有分區的,而當前進行了一次分區,

ALTER TABLE `USER`PARTITION BY HASH(id)PARTITIONS 1;

ALTER TABLE … PARTITION BY使用規格必須和CREATE TABLE … PARTITION BY的一樣,分區表的分區表達式中使用的所有列都必須是該表可能具有的每個唯一鍵的一部分

ALTER TABLE … PARTITION BY statement must follow the same rules as one created using CREATE TABLE … PARTITION BY

In other words, every unique key on the table must use every column in the table’s partitioning expression. (This also includes the table’s primary key, since it is by definition a unique key. This particular case is discussed later in this section.)

舉個例子,執行下面的分區SQL就是無效的,

ALTER TABLE `USER`PARTITION BY HASH(age)PARTITIONS 5;

在這里插入圖片描述
執行CREATE TABLE ... PARTITION BY對表t1和t2進行分區時,下面這種也是無效的,

CREATE TABLE t1 (col1 INT NOT NULL,col2 DATE NOT NULL,col3 INT NOT NULL,col4 INT NOT NULL,UNIQUE KEY (col1, col2)
)
PARTITION BY HASH(col3)
PARTITIONS 4;CREATE TABLE t2 (col1 INT NOT NULL,col2 DATE NOT NULL,col3 INT NOT NULL,col4 INT NOT NULL,UNIQUE KEY (col1),UNIQUE KEY (col3)
)
PARTITION BY HASH(col1 + col3)
PARTITIONS 4;

如果要進行分區,建議表中至少有一個唯一鍵,該鍵不包括分區表達式中使用的所有列,比如下面SQL就是有效的,

CREATE TABLE t1 (col1 INT NOT NULL,col2 DATE NOT NULL,col3 INT NOT NULL,col4 INT NOT NULL,UNIQUE KEY (col1, col2, col3)
)
PARTITION BY HASH(col3)
PARTITIONS 4;CREATE TABLE t2 (col1 INT NOT NULL,col2 DATE NOT NULL,col3 INT NOT NULL,col4 INT NOT NULL,UNIQUE KEY (col1, col3)
)
PARTITION BY HASH(col1 + col3)
PARTITIONS 4;

PARTITION BY的規則就不一一細說了,官網上有明確的解釋,接下來我們看看官網PARTITION BY RANGE的規則和用法,如果沒有唯一鍵(包括沒有主鍵),上述規則就不適用了,可以使用任意列進行分區,如下示例,

CREATE TABLE t_no_pk (c1 INT, c2 INT)
PARTITION BY RANGE(c1) (
PARTITION p0 VALUES LESS THAN (10),
PARTITION p1 VALUES LESS THAN (20),
PARTITION p2 VALUES LESS THAN (30),
PARTITION p3 VALUES LESS THAN (40)
);

沒有主鍵的t_no_pk表基本上很少見,這里可以忽略這種規則,如果有需要再來研究,
在這里插入圖片描述
正常場景,分區使用主鍵,比如下面建了一個訂單表,訂單id和訂單的創建時間作為聯合主鍵,然后再根據創建時間進行按月分區,

CREATE TABLE orders (id BIGINT NOT NULL,user_id BIGINT NOT NULL,order_status VARCHAR(20) NOT NULL,create_time DATETIME NOT NULL,PRIMARY KEY (id, create_time)	
)
PARTITION BY RANGE(YEAR(create_time)*100 + MONTH(create_time)) (
PARTITION p202501 VALUES LESS THAN (202501),
PARTITION p202502 VALUES LESS THAN (202502),
PARTITION p202503 VALUES LESS THAN (202503),
PARTITION p202504 VALUES LESS THAN (202504)
)
;

創建完后,可以執行下面SQL命令查看分區信息,

SELECT TABLE_SCHEMA, TABLE_NAME, PARTITION_NAME, PARTITION_METHOD, PARTITION_EXPRESSION, PARTITION_DESCRIPTION
FROM INFORMATION_SCHEMA.PARTITIONS
WHERE TABLE_SCHEMA = 'testdemo' AND TABLE_NAME = 'orders';

在這里插入圖片描述
Mock數據,可以發現當我們插入了不在分區范圍內的數據時會報錯,
在這里插入圖片描述
所以需要知行合一,你給數據庫分區了之后超過你分區范圍的數據都插不了數據庫那不是線上大問題?

可以在時間分區后面加一個兜底PARTITION p299912 VALUES LESS THAN (300001),避免出現這種情況,至少你百年去世后這個數據插入也不會有問題。

那么分區之后有什么好處呢?

  • 提升查詢效率;
  • 簡化表維護;

假設數據如下,
在這里插入圖片描述

1、查詢特定分區數據;

SELECT * FROM orders PARTITION (p202504);

如下圖,我們查到的是大于2025年2月且小于2025年4月,即2025年3月份的數據,
在這里插入圖片描述
2、使用了分區裁剪(Partition Pruning),當你在WHERE子句中指定了分區鍵的條件時,MySQL會自動利用分區裁剪來優化查詢。例如,

SELECT * FROM orders WHERE create_time = '2025-02-20 16:45:37';

使用EXPLAIN該SQL語句可以看到select_type = SIMPLE(即不需要使用union或子查詢的簡單select查詢),type = ALL即進行了全表掃描,但是走了partitions = p202503的分區,該分區的行數為2條記錄(rows = 2)
在這里插入圖片描述

3、刪除舊數據比DELETE快10倍;

ALTER TABLE orders TRUNCATE PARTITION p202502;

在這里插入圖片描述

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

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

相關文章

java_spring boot 中使用 log4j2 及 自定義layout設置示例

1. log4j2對比 原始Logback 優勢 對于 Spring Boot 3.x&#xff0c;Logback 是默認日志框架&#xff0c;但在高并發、異步日志場景下&#xff0c;Log4j2 通常表現更優。當業務百萬級用戶、微服務、日志量大時&#xff1a; ? 1. Logback&#xff08;默認 Spring Boot 集成&am…

記錄Webapi Excel 導出

文章目錄1、helper2、control3、前端 axios記錄webapi excel 導出File示例.NET8.0 NPOI2.731、helper using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using System.Data; using System.IO; /// <summary> /// 導出EXCEL /// </summary> public class Exce…

VPS服務器安全審計方案:從風險評估到防護實施

隨著云計算技術的快速發展&#xff0c;VPS服務器已成為企業信息化建設的重要基礎設施。隨之而來的安全威脅也日益增多&#xff0c;如何通過專業的安全審計方案保障VPS服務器的穩定運行成為關鍵課題。本文將系統闡述從漏洞掃描到應急響應的全周期安全審計實施策略&#xff0c;幫…

libmicrohttpd 入門

libmicrohttpd 是一個小型的 C 庫&#xff0c;用于在項目中嵌入 HTTP 服務器功能。它設計簡單、輕量級&#xff0c;適合需要 HTTP 接口但不想要大型 Web 服務器開銷的應用程序。 安裝 libmicrohttpd Linux 系統 在基于 Debian/Ubuntu 的系統上&#xff1a; bash sudo apt-…

【網絡】使用 DNAT 進行負載均衡時,若未配置配套的 SNAT,回包失敗

【網絡】iptables 1 概念 【網絡】iptables 2 查看規則 【網絡】使用 DNAT 進行負載均衡時&#xff0c;若未配置配套的 SNAT&#xff0c;回包失敗 【網絡】回包路由原理 使用 DNAT 進行負載均衡時&#xff0c;若未配置配套的 SNAT&#xff0c;后端服務器將直接回包給客戶端&am…

深入解析GCC:從編譯原理到嵌入式底層實戰

繼續更新編譯器底層系列&#xff01;&#xff01;&#xff01;硬核C語言的屠龍之術&#xff1a;從GCC到匯編的底層征途&#xff08;一&#xff09;總綱&#xff1a; 恭喜你&#xff0c;決定踏上這條通往嵌入式大佬的硬核之路。這條路的起點&#xff0c;不是C語言的語法書&#…

最新MySQL面試題(2025超詳細版)

2025最新超詳細MySQL面試題 文章目錄2025最新超詳細MySQL面試題[toc]一、 SQL 和基本操作1. SQL的執行順序2. 如何優化MySQL查詢3. 常用的聚合函數4. 數據庫事務5. 事務的四大特性(ACID)6. 視圖7. MySQL中使用LIMIT子句進行分頁8. MySQL中使用變量和用戶定義的函數9. MySQL中的…

Spring Retry實戰指南_讓你的應用更具韌性

1 Spring Retry概述 1.1 什么是Spring Retry Spring Retry是Spring生態系統中的一個重要組件,專門用于處理應用程序中的重試邏輯。在分布式系統和微服務架構中,網絡通信、外部服務調用、數據庫訪問等操作都可能因為各種原因而失敗,如網絡抖動、服務暫時不可用、資源競爭等…

大數據畢業設計選題推薦-基于大數據的1688商品類目關系分析與可視化系統-Hadoop-Spark-數據可視化-BigData

?作者主頁&#xff1a;IT畢設夢工廠? 個人簡介&#xff1a;曾從事計算機專業培訓教學&#xff0c;擅長Java、Python、PHP、.NET、Node.js、GO、微信小程序、安卓Android等項目實戰。接項目定制開發、代碼講解、答辯教學、文檔編寫、降重等。 ?文末獲取源碼? 精彩專欄推薦?…

【Grafana】grafana-image-renderer配合python腳本實現儀表盤導出pdf

背景 os&#xff1a;centos7Grafana&#xff1a;v12grafana-image-renderer&#xff1a;v4.0.10插件&#xff1a;否grafana-image-renderer可以以插件形式啟動&#xff0c;也可以以單獨服務啟動&#xff0c;在centos7插件啟動時&#xff0c;報錯glibc版本太低&#xff0c;未找到…

靜/動態庫 IIC(arm) day58

十七&#xff1a;動態庫和靜態庫 庫&#xff1a;一堆可執行二進制文件的集合&#xff0c;由若干個.o文件歸并生成 一&#xff1a;靜態(鏈接)庫&#xff1a;libxxx.a 生成一個獨立的可執行程序(運行時僅需要一個文件即可) 使用方便 不需要安裝 文件比較大 多個程序使用同一個靜態…

uniapp 手寫簽名組件開發全攻略

引言在移動應用開發中&#xff0c;手寫簽名功能是一個常見的需求&#xff0c;特別是在電子合同、審批流程、金融交易等場景中。本文將詳細介紹如何基于uni-app框架開發一個高性能、功能豐富的手寫簽名組件&#xff0c;并分享開發過程中的技術要點和最佳實踐。組件概述這個簽名組…

理解JavaScript中的函數賦值和調用

&#x1f468; 作者簡介&#xff1a;大家好&#xff0c;我是Taro&#xff0c;全棧領域創作者 ?? 個人主頁&#xff1a;唐璜Taro &#x1f680; 支持我&#xff1a;點贊&#x1f44d;&#x1f4dd; 評論 ??收藏 文章目錄前言一、函數賦值二、函數調用三、 代碼示例總結前言…

交叉編譯 手動安裝 SQLite 庫 移植ARM

# 下載源碼 wget https://www.sqlite.org/2023/sqlite-autoconf-3420000.tar.gz tar -xzf sqlite-autoconf-3420000.tar.gz cd sqlite-autoconf-3420000cd /home/lxh/sqlite-autoconf-3420000 make distclean //清除下&#xff0c;因為我安裝失敗過。 ./configure --hostarm-…

翻譯記憶庫(TMX)與機器翻譯的結合應用

更多內容請見: 機器翻譯修煉-專欄介紹和目錄 文章目錄 一、核心概念解析 1.1 翻譯記憶庫 (Translation Memory, TM) 1.2 翻譯記憶交換格式 (Translation Memory eXchange, TMX) 二、為何要將兩者結合? 2.1 TM和MT的優勢是高度互補的 2.2 TMX在結合中的關鍵作用 2.3 TMX與MT的…

SpringBoot中集成eclipse.paho.client.mqttv3實現mqtt客戶端并支持斷線重連、線程池高并發改造、存儲入庫mqsql和redis示例業務流程,附資源下載

場景 SpringBoot整合MQTT服務器實現消息的發送與訂閱(推送消息與接收推送)&#xff1a; SpringBoot整合MQTT服務器實現消息的發送與訂閱(推送消息與接收推送)_服務端接收mqtt消息-CSDN博客 上面SpringBoot集成MQTT使用的是spring-integration-mqtt依賴&#xff0c;也是經常使…

【考研408數據結構-08】 圖論基礎:存儲結構與遍歷算法

&#x1f4da; 【考研408數據結構-08】 圖論基礎&#xff1a;存儲結構與遍歷算法 &#x1f3af; 考頻&#xff1a;????? | 題型&#xff1a;選擇題、綜合應用題、算法設計題 | 分值&#xff1a;約8-15分 引言 想象你正在規劃一次跨省自駕游&#xff0c;面前攤開一張復雜的…

SQL查詢語句的執行順序

好的&#xff0c;我們來詳細講解一下 SQL 查詢語句的執行順序。 很多人會誤以為 SQL 的執行順序就是我們寫的順序&#xff08;SELECT -> FROM -> WHERE -> GROUP BY -> HAVING -> ORDER BY&#xff09;&#xff0c;但實際上&#xff0c;數據庫引擎在底層處理查詢…

【Android】OKHttp網絡請求原理和弱網優化

【Android】OKHttp網絡請求原理和弱網優化 1. OkHttp 網絡請求原理 OkHttp 的請求過程可以分為 四個關鍵階段&#xff1a; &#xff08;假設你是通過 OkHttpClient.newCall(request).enqueue(callback) 發的請求&#xff09; OkHttpClient│▼ Dispatcher (調度器)│▼ RealC…

概率論基礎教程第4章 隨機變量(四)

4.7 泊松隨機變量 定義 泊松隨機變量&#xff1a;如果一個取值于 $ 0, 1, 2, \ldots $ 的隨機變量對某一個 $ \lambda > 0 $&#xff0c;其分布列為&#xff1a; p(i)P{Xi}e?λλii!i0,1,2,?(7.1) \boxed{p(i) P\{X i\} e^{-\lambda} \frac{\lambda^i}{i!} \qquad i 0…