主頁 > 資料庫 > MySQL 磁區表,為什么磁區鍵必須是主鍵的一部分?

MySQL 磁區表,為什么磁區鍵必須是主鍵的一部分?

2021-12-22 06:28:10 資料庫

隨著業務的不斷發展,資料庫中的資料會越來越多,相應地,單表的資料量也會越到越大,大到一個臨界值,單表的查詢性能就會下降,

這個臨界值,并不能一概而論,它與硬體能力、具體業務有關,

雖然在很多 MySQL 運維規范里,都建議單表不超過 500w、1000w,

但實際上,我在生產環境,也見過大小超過 2T,記錄數過億的表,同時,業務不受影響,

單表過大時,業務通常會考慮兩種拆分方案:水平切分和垂直切分,

 

水平拆分 VS 垂直拆分

水平切分,拆分的維度是行,一般會根據某種規則或演算法將表中的記錄拆分到多張表中,

拆分后的表既可在一個實體,也可在多個不同實體中,如果是后者,又會涉及到分布式事務,

垂直切分,拆分的維度是列,一般是將列拆分到多個業務模塊中,這種拆分更多的是上層業務的拆分,

從改造的復雜程度來說,前者小于后者,

所以,在單表資料量過大時,業界用得較多的還是水平拆分,

常見的水平拆分方案有:分庫分表、磁區表,

雖然分庫分表是一個比較徹底的水平拆分方案,但一方面,它的改造需要一定的時間;另一方面,它對開發的能力也有一定的要求,相對來說,磁區表就比較簡單,也無需業務改造,

 

磁區表

很多人可能會認為 MySQL 的優勢在于 OLTP 應用,對于 OLAP 應用就不太適合,所以,也不太推薦磁區表這種偏 OLAP 的特性,

但實際上,對于某些業務型別,還是比較適合使用磁區表的,尤其是那些有明顯冷熱資料之分,且資料的冷熱與時間相關的業務,

下面,我們看看磁區表的優點:

  1. 提升查詢性能

    對于磁區表的查詢操作,如果查詢條件中包含磁區鍵,則這個查詢操作就只會被下推到符合條件的磁區內進行,無關磁區將自動過濾掉,

    在資料量比較大的情況下,能提升查詢速度,

  2. 對業務透明

    將表從一個非磁區表轉換為磁區表,業務端無需做任何改造,

  3. 管理方便

    在對單個磁區進行洗掉、遷移和維護時,不會影響到其它磁區,

    尤其是針對單個磁區的洗掉(DROP)操作,避免了針對這個磁區所有記錄的 DELETE 操作,

遺憾的是,MySQL 磁區表不支持并行查詢,理論上,當一個查詢涉及到多個磁區時,磁區與磁區之間應進行并行查詢,這樣才能充分利用多核 CPU 資源,

但 MySQL 并不支持,包括早期的官方檔案,也提到了這個問題,也將這個功能的實作放到了優先級串列中,

These features are not currently implemented in MySQL Partitioning, but are high on our list of priorities.

- Queries involving aggregate functions such as SUM() and COUNT() can easily be parallelized. A simple example of such a query might be SELECT salesperson_id, COUNT(orders) as order_total FROM sales GROUP BY salesperson_id;. By “parallelized,” we mean that the query can be run simultaneously on each partition, and the final result obtained merely by summing the results obtained for all partitions.

- Achieving greater query throughput in virtue of spreading data seeks over multiple disks.

 

MySQL 8.0 中磁區表的變化

在 MySQL 5.7 中,對于磁區表,有個很重大的更新,即 InnoDB 存盤引擎原生支持了磁區,無需再通過 ha_partition 介面來實作,

所以,在 MySQL 5.7 中,如果要創建基于 MyISAM 存盤引擎的磁區表,會提示 warning ,

The partition engine, used by table 'sbtest.t_range', is deprecated and will be removed in a future release. Please use native partitioning instead.

而在 MySQL 8.0 中,則更為徹底,server 層移除了 ha_partition 介面代碼,

如果要使用磁區表,只能使用支持原生磁區的存盤引擎,在 MySQL 8.0 中,就只有 InnoDB,

這就意味著,在 MySQL 8.0 中,如果要創建 MyISAM 磁區表,基本上就不可能了,

這也從另外一個角度說明了為什么生產上不建議使用 MyISAM 表,

mysql> CREATE TABLE t_range (
    ->     id INT,
    ->     name VARCHAR(10)
    -> ) ENGINE = MyISAM
    -> PARTITION BY RANGE (id) (
    ->     PARTITION p0 VALUES LESS THAN (5),
    ->     PARTITION p1 VALUES LESS THAN (10)
    -> );
ERROR 1178 (42000): The storage engine for the table doesn't support native partitioning

 

為什么磁區鍵必須是主鍵的一部分?

在使用磁區表時,大家常常會碰到下面這個報錯,

mysql> CREATE TABLE opr (
    ->     opr_no INT,
    ->     opr_date DATETIME,
    ->     description VARCHAR(30),
    ->     PRIMARY KEY (opr_no)
    -> )
    -> PARTITION BY RANGE COLUMNS (opr_date) (
    ->     PARTITION p0 VALUES LESS THAN ('20210101'),
    ->     PARTITION p1 VALUES LESS THAN ('20210102'),
    ->     PARTITION p2 VALUES LESS THAN MAXVALUE
    -> );
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function (prefixed columns are not considered).

即磁區鍵必須是主鍵的一部分,

上面的 opr 是一張操作流水表,其中,opr_no 是操作流水號,一般都會被設定為主鍵,opr_date 是操作時間,基于操作時間來進行磁區,是一個常見的磁區場景,

為了突破這個限制,可將 opr_date 作為主鍵的一部分,

mysql> CREATE TABLE opr (
    ->     opr_no INT,
    ->     opr_date DATETIME,
    ->     description VARCHAR(30),
    ->     PRIMARY KEY (opr_no, opr_date)
    -> )
    -> PARTITION BY RANGE COLUMNS (opr_date) (
    ->     PARTITION p0 VALUES LESS THAN ('20210101'),
    ->     PARTITION p1 VALUES LESS THAN ('20210102'),
    ->     PARTITION p2 VALUES LESS THAN MAXVALUE
    -> );
Query OK, 0 rows affected (0.04 sec)

 

但是這么創建,又會帶來一個新的問題,即對于同一個 opr_no ,可插入到不同磁區中,如下所示:

mysql> insert into opr values(1,'2020-12-31 00:00:01','abc');
Query OK, 1 row affected (0.00 sec)

mysql> insert into opr values(1,'2021-01-01 00:00:01','abc');
Query OK, 1 row affected (0.00 sec)

mysql> select * from opr partition (p0);
+--------+---------------------+-------------+
| opr_no | opr_date            | description |
+--------+---------------------+-------------+
|      1 | 2020-12-31 00:00:01 | abc         |
+--------+---------------------+-------------+
1 row in set (0.00 sec)

mysql> select * from opr partition (p1);
+--------+---------------------+-------------+
| opr_no | opr_date            | description |
+--------+---------------------+-------------+
|      1 | 2021-01-01 00:00:01 | abc         |
+--------+---------------------+-------------+
1 row in set (0.00 sec)

這實際上違背了業務對于 opr_no 的唯一性要求,

 

既然這樣,有的童鞋會建議給 opr_no 添加個唯一索引,But,現實是殘酷的,

mysql> create unique index uk_opr_no on opr (opr_no);
ERROR 1503 (HY000): A UNIQUE INDEX must include all columns in the table's partitioning function (prefixed columns are not considered)

即便是添加唯一索引,磁區鍵也必須包含在唯一索引中,

總而言之,對于 MySQL 磁區表,無法從資料庫層面保證非磁區列在表級別的唯一性,只能確保其在磁區內的唯一性,

這也是 MySQL 磁區表所為人詬病的地方之一,

 

但實際上,這個鍋讓 MySQL 背并不合適,對于 Oracle 索引組織表( InnoDB 即是索引組織表),同樣也有這個限制,

Oracle 官方檔案( http://docs.oracle.com/cd/E11882_01/server.112/e40540/schemaob.htm#CNCPT1514),在談到索引組織表(Index-Organized Table,簡稱 IOT)的特性時,就明確提到了 “磁區鍵必須是主鍵的一部分”,

Note the following characteristics of partitioned IOTs:

   - Partition columns must be a subset of primary key columns.
   - Secondary indexes can be partitioned locally and globally.
   - OVERFLOW data segments are always equipartitioned with the table partitions.

 

下面,我們看看剛開始的建表 SQL ,在 Oracle 中的執行效果,

SQL> CREATE TABLE opr_oracle (
  2      opr_no NUMBER,
  3      opr_date DATE,
  4      description VARCHAR2(30),
  5      PRIMARY KEY (opr_no)
  6  )
  7  ORGANIZATION INDEX
  8  PARTITION BY RANGE (opr_date) (
  9      PARTITION p0 VALUES LESS THAN (TO_DATE('20170713', 'yyyymmdd')),
 10      PARTITION p1 VALUES LESS THAN (TO_DATE('20170714', 'yyyymmdd')),
 11      PARTITION p2 VALUES LESS THAN (MAXVALUE)
 12  );
PARTITION BY RANGE (opr_date) (
                    *
ERROR at line 8:
ORA-25199: partitioning key of a index-organized table must be a subset of the
primary key

同樣報錯,

注意,這里指定了 ORGANIZATION INDEX ,創建的是索引組織表,

看來,磁區鍵必須是主鍵的一部分并不是 MySQL 的限制,而是索引組織表的限制,

之所以對索引組織表有這樣的限制,個人認為,還是基于性能考慮,

假設磁區鍵和主鍵是兩個不同的列,在進行插入操作時,雖然也指定了磁區鍵,但還是需要掃描所有磁區才能判斷插入的主鍵值是否違反了唯一性約束,這樣的話,效率會比較低下,違背了磁區表的初衷,

而對于堆表則沒有這樣的限制,

在堆表中,主鍵和表中的資料是分開存盤的,在判斷插入的主鍵值是否違反唯一性約束時,只需利用到主鍵索引,

 

但與 MySQL 不一樣的是,Oracle 實作了全域索引,所以針對上面的,同一個 opr_no,允許插入到不同磁區中的問題,可通過全域唯一索引來規避,

SQL> CREATE TABLE opr_oracle (
  2      opr_no NUMBER,
  3      opr_date DATE,
  4      description VARCHAR2(30),
  5      PRIMARY KEY (opr_no, opr_date)
  6  )
  7  ORGANIZATION INDEX
  8  PARTITION BY RANGE (opr_date) (
  9      PARTITION p0 VALUES LESS THAN (TO_DATE('20170713', 'yyyymmdd')),
 10      PARTITION p1 VALUES LESS THAN (TO_DATE('20170714', 'yyyymmdd')),
 11      PARTITION p2 VALUES LESS THAN (MAXVALUE)
 12  );

Table created.

SQL> create unique index uk_opr_no on opr_oracle (opr_no);

Index created.

SQL> insert into opr_oracle values(1,to_date('2020-12-31 00:00:01','yyyy-mm-dd hh24:mi:ss'),'abc');

1 row created.

SQL> insert into opr_oracle values(1,to_date('2020-12-31 00:00:01','yyyy-mm-dd hh24:mi:ss'),'abc');
insert into opr_oracle values(1,to_date('2020-12-31 00:00:01','yyyy-mm-dd hh24:mi:ss'),'abc')
*
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.SYS_IOT_TOP_87350) violated

但 MySQL 卻無能為力,之所以會這樣,是因為 MySQL 磁區表只實作了本地磁區索引(Local Partitioned Index),而沒有實作 Oracle 中的全域索引(Global Index),

 

本地磁區索引 VS 全域索引

本地磁區索引和全域索引的原理圖如下所示:

 

 

 

結合原理圖,我們來看看兩種索引之間的區別:

  1. 本地磁區索引同時也是磁區索引,磁區索引和表磁區之間是一一對應的,

    而全域索引,既可以是磁區的,也可以是不磁區的,

    如果是全域磁區索引,一個磁區索引可對應多個表磁區,同樣,一個表磁區也可對應多個磁區索引,

  2. 對本地磁區索引的管理操作只會影響到單個磁區,不會影響到其它磁區,

    而對全域磁區索引的管理操作會造成整個索引的失效,當然,這一點可通過 UPDATE INDEXES 子句加以規避,

  3. 本地磁區索引只能保證磁區內的唯一性,無法保證表級別的唯一性,但全域磁區可以,

  4. 在 Oracle 中,無論是索引組織表還是堆表,如果要創建本地唯一索引,同樣也要求磁區鍵必須是唯一鍵的一部分,

    SQL> create unique index uk_opr_no_local on opr_oracle(opr_no) local;
    create unique index uk_opr_no_local on opr_oracle(opr_no) local
                                           *
    ERROR at line 1:
    ORA-14039: partitioning columns must form a subset of key columns of a UNIQUE
    index

 

總結

1. MySQL 磁區表關于“磁區鍵必須是唯一鍵(主鍵和唯一索引)的一部分”的限制,本質上是索引組織表的限制,

2. MySQL 磁區表只實作了本地磁區索引,沒有實作全域索引,所以無法保證非磁區列的全域唯一,

如果要保證非磁區列的全域唯一,只能依賴業務實作了,

3. 不推薦使用 MyISAM 磁區表,當然,任何場景都不推薦使用 MyISAM 表,

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/388981.html

標籤:其他

上一篇:又拿獎了!騰訊云原生資料庫TDSQL-C斬獲2021PostgreSQL中國最佳資料庫產品獎

下一篇:又拿獎了!騰訊云原生資料庫TDSQL-C斬獲2021PostgreSQL中國最佳資料庫產品獎

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more