MySQL學習點滴 --分區表

来源:https://www.cnblogs.com/dogtwo0214/archive/2019/05/21/10894851.html
-Advertisement-
Play Games

寫在前面:筆者之前也有一些MySQL方面的筆記,其中部分內容來自極客時間中丁奇老師的課程。後經園友提醒,這個做法確實不太好。之後我仍會繼續更新一下MySQL方面的學習記錄,在自己理解之後用自己的方式記錄下來。學習與記錄,也是我寫博客的初衷。 概述: 分區功能並不是在存儲引擎層完成的,因此很多存儲引擎 ...


  寫在前面:筆者之前也有一些MySQL方面的筆記,其中部分內容來自極客時間中丁奇老師的課程。後經園友提醒,這個做法確實不太好。之後我仍會繼續更新一下MySQL方面的學習記錄,在自己理解之後用自己的方式記錄下來。學習與記錄,也是我寫博客的初衷。

 

概述:

  分區功能並不是在存儲引擎層完成的,因此很多存儲引擎包括InnoDB, MyISAM, NDB等都支持分區功能。但也並不是所有的存儲引擎都支持分區。在使用分區前,首先要瞭解一下存儲引擎對分區的支持情況。如果不作特殊說明,預設是在InnoDB下進行說明。 

  所謂分區,指的是將一個表或索引分解為更小的部分。從物理層面來說,可能是分成了N個物理分區,每個分區都是獨立的。從邏輯上來說,這N個物理分區仍是一個表或一個索引。

  分區可以分為兩大類:

  1. 水平分區,指的是將同一表中不同行的記錄分配到不同的物理文件中。
  2. 垂直分區,指的是將同一表中不同列的記錄分配到不同的物理文件中。

  MySQL在5.1版本中加入了對水平分區的支持,其最新版本是否支持垂直分區筆者暫未考證。網上有一些關於MySQL垂直分區的內容,大都也是在業務層面將表進行拆分,“手動的”垂直分區。

  可以通過命令 SHOW PLUGINS; 來查看是否開啟了分區功能。(partition的status值為ACTIVE)。

  MySQL支持下麵幾種類型的分區:

  1. RANGE分區:行數據基於一個給定連續區間的列值被放入分區。從5.5版本開始支持RANGE COLUMNS的分區。
  2. LIST分區:和RANGE分區類似,只是LIST分區面向的是離散的值。從5.5版本開始支持LIST COLUMNS的分區。
  3. HASH分區:根據用戶自定義的表達式的返回值進行分區,返回值不能為負數。
  4. KEY分區:根據MySQL資料庫提供的哈希函數來進行分區。

  不論創建哪種類型的分區,如果表中存在主鍵或唯一索引,分區列必須是唯一索引的一個組成部分。(這裡筆者初次接觸時還鬧了個笑話。上面提到了MySQL支持的是水平分區,也就是說把不同的行記錄分配到不同的物理文件中,那為啥還有個分區列?分區列還必須是唯一索引的一個組成部分?其實是這樣的,在分區表中如果要插入一條記錄,肯定要先確定應該插入到哪個分區里去。而確定它屬於哪個分區就是依靠了分區列的值,根據這個值再按照不同分區自身的規則,就可以確定這條記錄應該被分配到哪個分區了)。唯一索引可以是允許NULL值的,並且分區列只要是唯一索引的一個組成部分,不需要整個唯一索引分區列都是分區列。如唯一索引是 UNIQUE KEY(a,b),分區列可以只指定a列,PARTITION BY HASH(a);

  如果創建表時沒有指定主鍵,唯一索引,那麼可以指定任何一個列為分區列。

分區類型:

RANGE分區:

  這是最常用的一種分區,我們來看一個簡單的例子:

CREATE TABLE range_t(
id INT
)ENGINE = INNODB
PARTITION BY RANGE (id)(
PARTITION p0 VALUES LESS THAN (10),
PARTITION p1 VALUES LESS THAN (20)
);

  由建表語句很容易看出我們把range_t分成了p0,p1兩部分。由於Range分區是給連續區間分區,因此p1的區間範圍其實[10,20)。此處需要註意的是,如果僅僅按照上面我們的分區來的話,是不能向表range_t中插入id大於20的記錄的。

  

  這種情況下我們可以添加一個MAXVALUE值的分區,MAXVALUE可以理解為正無窮,因此區間可以改變為[20,MAXVALUE).

ALTER TABLE range_t ADD PARTITION(
partition p2 values less than maxvalue);

  range分區的一個典型的應用場景是記錄與日期相關的記錄。例如要記錄某種交易記錄,可以按年份時間進行分區。如

...
PARTITION BY RANGE (YEAR(date))(
PARTITION p2017 VALUES LESS THAN (2018), PARTITION p2018 VALUES LESS THAN (2019), PARTITION p2019 VALUES LESS THAN (2020) );

  根據date所屬的年份進行分區,year函數取得的值如果小於2019就歸檔到p2018分區。這樣做有這麼一些好處。首先是方便管理,如果我們要刪除18年的數據,可以直接對分區p2018進行刪除。 alter table t drop partition p2018; 另一方面,這樣分區也可以加快某些查詢的速度。同樣以p2018分區進行舉例,如果你確定要查詢的範圍只在2018這個區間內,可以直接對這個分區進行查詢:select * from t partition(p2018);

  有一點需要註意,優化器可以對range分區中的部分函數(如YEAR(),TO_DAYS()...)進行優化選擇,而對形如YEAR(date)*100 + MONTH(date)這樣的分區條件是無能為力的。

 

LIST分區:

  list分區和range分區很相似,區別在於list分區的值是離散的。例如建表語句:

CREATE TABLE list_t(
a INT,
b INT
)ENGINE = INNODB
PARTITION BY LIST(b)(
    PARTITION p0 values IN(1,3,5,7),
    PARTITION p1 values IN(2,4,6,8)   
);

  和range分區一樣,如果你插入的記錄的分區列的值不在list分區的範圍內,MySQL資料庫會拋出異常。另外,如果一次插入多個行的記錄,而這些記錄當中存在分區未定義的值時,MyISAM和InnoDB存儲引擎的處理方式不同。MyISAM會將之前的行資料庫都插入,但之後的不會插入。而InnoDB會將其視為一個事務,因此沒有任何事務插入。

  MyISAM:

  

  Innodb:

  

 

HASH分區:

  Hash分區的目的是將數據均勻地分部到預先定義的各個分區中,儘量保證各分區的數據量相等。在RANGE和LIST分區中,必須明確指定一個給定的列值活列值所在的集合範圍,而HASH分區中,MySQL自動完成這些工作,用戶所要做的只是基於將要進行哈希分區的列指定一個列值或表達式,以及指定被分區的表將要被分隔成幾部分。一個Hash分區的建表語句例子如下:

CREATE TABLE hash_t(
a INT,
b INT
)ENGINE = InnoDB
PARTITION BY HASH(a+b)
PARTITIONS 4;

  如上所述,用戶所要做的只是基於將要進行哈希分區的列指定一個列值或表達式。這裡我們使用a+b的值來作為進行hash的值,當然你也可以直接使用欄位a或b,或是別的表達式。另外,後面的PARTITIONS 4;代表了要分隔成幾個區,這裡要求是一個非負整數,預設值是1.

 

KEY分區:

  Key分區和Hash分區很類似,區別在於hash分區使用用戶定義的函數進行分區,key分區使用MySQL資料庫提供的函數進行分區。對於NDB Cluster引擎,MySQL使用MD5函數來進行分區,對於其他引擎,MySQL資料庫使用其內部哈希函數,這些函數基於與Password()一樣的運算規則。

 

COLUMNS分區:

  前面介紹的這幾種分區有一個共同條件,即數據必須是整型(interger),如果不是整形則需要通過函數將其轉化為整型,如YEAR()等。從5.5版本開始,MySQL支持COLUMNS分區,可以理解成是Range分區和list分區的一種優化,它允許直接使用非整形的數據進行分區,分區根據類型直接比較而得,不需要額外的轉型處理。此外,Range COLUMNS允許對多個列的值進行分區。COLUMNS分區所支持的類型:

  • 所有的整型類型,如INT,SMALLINT,TINYINT,BIGINT。註意,FLOAT和DECIMAL不支持。
  • 日期類型,僅支持DATE和DATETIME。
  • 字元串類型,如CHAR,VARCHAR,BINARYHE VARBINARY。註意,BLOB和TEXT不支持。

  Range Columns對多個列的值進行分區的例子如下:

CREATE TABLE range_column_t(
a INT,
b INT,
c char(3)
)engine = InnoDB
PARTITION BY RANGE COLUMNS(a,b,c)(
PARTITION p0 VALUES LESS THAN (5,10,'c'),
PARTITION p1 VALUES LESS THAN (10,20,'m'),
PARTITION p2 VALUES LESS THAN (30,50,'z')
);

  到這裡,你應該和我一樣有一個疑問,如果我三個值分別屬於不同的區間則會被插入到哪個分區呢。比如插入這麼一條記錄:insert into range_column_t values(4,9,'n'); a,b欄位的值都在p0分區範圍內,c的值p2分區範圍內,實際上也插入成功了。我們來看看結果吧:

  如果我們再插入一條記錄:insert into range_column_t values(25,15,'a');查看結果如下:

  看來這種方式下,是按照分區列的順序進行分區的,滿足第一個條件後就會直接被分配到對應分區。

 

子分區:

  子分區是在分區的基礎上再進行分區,有時也稱這種分區為複合分區。MySQL資料庫允許在Range和List的分區上再進行Hash分區或Key的子分區。一個建立子分區的例子:

CREATE TABLE sub_t(
a INT,
b DATE
)engine = InnoDB
PARTITION BY RANGE(YEAR(b))
SUBPARTITION BY HASH(TO_DAYS(b))
SUBPARTITIONS 2 (
    PARTITION p0 VALUES LESS THAN (1990),
    PARTITION p1 VALUES LESS THAN (2000),
    PARTITION p2 VALUES LESS THAN MAXVALUE   
);

  關於子分區,有幾個地方需要註意一下:

  • 每個子分區的數量必須相同。
  • 要在一個分區表的任何分區上使用SUBPARTITION來明確定義任何子分區,就必須定義所有的子分區。
  • 每個SUBPARTITION子句必須包括子分區的一個名字
  • 子分區的名字必須是唯一的。

NULL值:

  MySQL資料庫允許對NULL值做分區,但處理方式可能不同於其他資料庫。在MySQL的分區中,Null值被認為總是小於任何一個非NULL值。並且對於不同的分區類型,處理方式也稍有不同。

  • 對於Range分區,Null值會被放入最左邊的分區。因此,如果刪除最左側的分區,假設該分區是定義是 LESS THAN 10,那麼刪除的實際上是小於10的所有記錄和包含Null值的記錄。
  • 在List分區中則必須顯示的指出哪個分區中放入Null值,否則會報錯。
  • 而在HASH和Key分區中,任何分區函數都會將含有NULL值的記錄返回為0。

分區和性能:

  其實有些類似於索引,並不是說無腦地添加索引,或是使用分區,資料庫的查詢就會更快。我們真正要做的是根據實際業務需求去具體的看待問題,如前面提到的按時間記錄的交易記錄的表,假設有這樣的一張大表,並且可以明確的按照時間分區,且需要頻繁訪問。那麼確實是可以使用分區來提高效率,每次查詢時儘量只訪問對應的分區即可。

  但實際情況中也可能存在這麼一種類型的表,它的數據量也很大,訪問也很頻繁。但每次可能只是會通過索引去訪問幾條記錄,而不需要一次返回很多很多記錄。這種情況下,分區可能會帶來不好的影響。我們知道,正常情況下B+樹索引(MySQL索引採用B+樹結構)只需要2~3次IO操作即可找到對應的記錄。如果盲目地使用分區,反而可能會增加IO操作的次數。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.DATE、DATETIME和TIMESTAMP 表達的時間範圍 2.DATETIME和TIMESTAMP 最大時間精確度 5.7 之後的版本(其實應該說5.6.5),在預設的秒精確度上,可以帶小數,最多帶6位小數,即可以精確到 microseconds (6 digits) precision。 ...
  • -U表示用戶-h表示主機-p表示埠號-t表示表名-f表示備份後的sql文件的名字-d表示要恢複數據庫名 一、打開cmd 進入postgresql安裝路徑下的bin文件夾,以我的為例: -U表示用戶-h表示主機-p表示埠號-t表示表名-f表示備份後的sql文件的名字-d表示要恢複數據庫名 一、打開 ...
  • MS SQL Server的COALESCE函數是從一系列表達式中返回第一個NOT NULL的值。 檢查[B],[Q],[S],[T],[U]的值: 檢查順序[B]->[Q]->[S]->[T]->[U],只要一遇上NOT NULL時,即刻返回。 IF OBJECT_ID('tempdb.dbo.# ...
  • 清理監聽日誌處理的方法1:首先停止監聽服務進程(tnslsnr)記錄日誌。lsnrctl ?set log_status off;? 2:將監聽日誌文件(listener.log)複製一份,以listener.log.yyyymmdd格式命名cp listener.log listener.log. ...
  • 數據完整性: 數據完整性要求資料庫中的數據具有“準確性”。如果兩個更多或者更多的表由於其存儲的信息相關聯,那麼只要修改了其中一個表,與之相關的所有表都要做出相應的修改,如果不這樣做,存儲的數據會不再準確,也就失去了數據完整性。 為了實現數據完整性,資料庫需要做一下兩方面的工作。 (1)檢驗每行數據是 ...
  • 前陣子有一個網友在群里問了一個關於Oracle資料庫的TX鎖問題,問題原文如下: 請教一個問題: 兩個會話執行不同的delete語句,結果都是刪除同一個行。先執行的會話里where條件不加索引走全表掃描,表很大,執行很慢;後執行的用where條件直接用rowid進行delete。 Oracle的什麼... ...
  • 最近在雲伺服器上安裝mysql 啟動時報錯了,從錯誤中可以看出,定位在pid文件上,有三種解決方案 1、重啟伺服器:因為伺服器更新時,可能會禁用某些守護進程,重啟後即可恢復 2、刪除配置文件,重啟試試 先備份一下 mv /etc/my.cnf /etc/my.cnf.backup ,重啟mysql服 ...
  • 剛有網友問及,第一列都需要由每一行的數據使用逗號串連起來。 Insus.NET先讓其參考: 《數據表列值轉換為逗號分隔字元串》https://www.cnblogs.com/insus/p/10848578.html 動態實現,因此Insus.NET試寫: CREATE TABLE #t ([qlr ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...