MySQL 8.4 參考手冊  /  分區  /  分區的限制與約束

26.6 分區的限制與約束

本節討論目前 MySQL 分區支援的限制與約束。

禁止的建構。 分區運算式中不允許下列建構

  • 儲存程序、儲存函數、可載入函數或外掛程式。

  • 宣告的變數或使用者變數。

如需分區運算式中允許的 SQL 函數清單,請參閱第 26.6.3 節,「與函數相關的分區限制」

算術和邏輯運算子。 在分區運算式中允許使用算術運算子 +-*。但是,結果必須是整數值或 NULL(除非是 [LINEAR] KEY 分區,如本章其他部分所述;如需更多資訊,請參閱第 26.2 節,「分區類型」)。

也支援 DIV 運算子;不允許使用 / 運算子。

分區運算式中不允許使用位元運算子 |&^<<>>~

伺服器 SQL 模式。 採用使用者定義分區的表格不會保留建立時生效的 SQL 模式。如本手冊其他部分所述(請參閱第 7.1.11 節,「伺服器 SQL 模式」),許多 MySQL 函數和運算子的結果可能會根據伺服器 SQL 模式而變更。因此,在建立分區表格後隨時變更 SQL 模式可能會導致這類表格的行為發生重大變更,而且很容易導致資料損毀或遺失。基於這些原因,強烈建議您在建立分區表格後,切勿變更伺服器 SQL 模式

為了說明伺服器 SQL 模式中的一個變更導致分區表格無法使用,請考慮下列 CREATE TABLE 陳述式,只有在 NO_UNSIGNED_SUBTRACTION 模式生效時才能成功執行

mysql> SELECT @@sql_mode;
+------------+
| @@sql_mode |
+------------+
|            |
+------------+
1 row in set (0.00 sec)

mysql> CREATE TABLE tu (c1 BIGINT UNSIGNED)
    ->   PARTITION BY RANGE(c1 - 10) (
    ->     PARTITION p0 VALUES LESS THAN (-5),
    ->     PARTITION p1 VALUES LESS THAN (0),
    ->     PARTITION p2 VALUES LESS THAN (5),
    ->     PARTITION p3 VALUES LESS THAN (10),
    ->     PARTITION p4 VALUES LESS THAN (MAXVALUE)
    -> );
ERROR 1563 (HY000): Partition constant is out of partition function domain

mysql> SET sql_mode='NO_UNSIGNED_SUBTRACTION';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @@sql_mode;
+-------------------------+
| @@sql_mode              |
+-------------------------+
| NO_UNSIGNED_SUBTRACTION |
+-------------------------+
1 row in set (0.00 sec)

mysql> CREATE TABLE tu (c1 BIGINT UNSIGNED)
    ->   PARTITION BY RANGE(c1 - 10) (
    ->     PARTITION p0 VALUES LESS THAN (-5),
    ->     PARTITION p1 VALUES LESS THAN (0),
    ->     PARTITION p2 VALUES LESS THAN (5),
    ->     PARTITION p3 VALUES LESS THAN (10),
    ->     PARTITION p4 VALUES LESS THAN (MAXVALUE)
    -> );
Query OK, 0 rows affected (0.05 sec)

如果您在建立 tu 後移除 NO_UNSIGNED_SUBTRACTION 伺服器 SQL 模式,您可能無法再存取此表格

mysql> SET sql_mode='';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM tu;
ERROR 1563 (HY000): Partition constant is out of partition function domain
mysql> INSERT INTO tu VALUES (20);
ERROR 1563 (HY000): Partition constant is out of partition function domain

另請參閱第 7.1.11 節,「伺服器 SQL 模式」

伺服器 SQL 模式也會影響分區表格的複寫。來源和複本上不同的 SQL 模式可能會導致分區運算式的評估方式不同;這可能會導致資料在來源和複本的表格副本之間的分區分布不同,甚至可能導致在來源上成功插入分區表格的動作在複本上失敗。為了獲得最佳結果,您應該始終在來源和複本上使用相同的伺服器 SQL 模式。

效能考量。 下列清單列出分區作業對效能的一些影響

  • 檔案系統作業。 分區和重新分區作業(例如使用 PARTITION BY ...REORGANIZE PARTITIONREMOVE PARTITIONINGALTER TABLE)取決於實作的檔案系統作業。這表示這些作業的速度會受到檔案系統類型和特性、磁碟速度、交換空間、作業系統的檔案處理效率,以及與檔案處理相關的 MySQL 伺服器選項和變數等因素的影響。特別是,您應該確定已啟用 large_files_support,並且已正確設定 open_files_limit。透過啟用 innodb_file_per_table,可以讓涉及 InnoDB 表格的分區和重新分區作業更有效率。

    另請參閱最大分區數量

  • 表格鎖定。 一般而言,在表格上執行分區作業的程序會取得表格的寫入鎖定。從這類表格讀取資料的行為相對不受影響;在分區作業完成後,會立即執行擱置的 INSERTUPDATE 作業。如需 InnoDB 特定的此限制例外情況,請參閱分區作業

  • 索引;分區修剪。 如同未分區的表格,正確使用索引可以顯著加快分區表格的查詢速度。此外,設計分區表格和這些表格的查詢以利用分區修剪,可以大幅提升效能。如需更多資訊,請參閱第 26.4 節,「分區修剪」

    分區表格支援索引條件下推。請參閱第 10.2.1.6 節,「索引條件下推最佳化」

  • 使用 LOAD DATA 的效能。 在 MySQL 8.4 中,LOAD DATA 使用緩衝來提升效能。您應該注意,緩衝區會使用每個分區 130 KB 的記憶體來達成此目的。

最大分區數量。 對於未使用 NDB 儲存引擎的指定表格,最大可能分區數量為 8192。此數字包含子分區。

對於使用 NDB 儲存引擎的表格,最大可能的使用者定義分區數量取決於所使用的 NDB Cluster 軟體版本、資料節點數量和其他因素。如需更多資訊,請參閱NDB 和使用者定義分區

如果當您建立大量分區的表格(但小於最大值)時,遇到類似 從儲存引擎取得錯誤 ... 開啟檔案時資源不足 的錯誤訊息,您可以嘗試增加 open_files_limit 系統變數的值來解決此問題。但是,這取決於作業系統,而且可能並非在所有平台上都可行或建議;如需更多資訊,請參閱第 B.3.2.16 節,「找不到檔案和類似錯誤」。在某些情況下,由於其他疑慮,使用大量(數百個)分區也可能不建議,因此使用更多分區不會自動帶來更好的結果。

另請參閱檔案系統作業

分割的 InnoDB 資料表不支援外部鍵。 使用 InnoDB 儲存引擎的分割資料表不支援外部鍵。更具體地說,這表示以下兩個陳述為真:

  1. 任何使用使用者定義分割的 InnoDB 資料表定義,皆不得包含外部鍵參照;任何定義中包含外部鍵參照的 InnoDB 資料表,皆不得進行分割。

  2. 任何 InnoDB 資料表定義,皆不得包含對使用者分割資料表的外部鍵參照;任何具有使用者定義分割的 InnoDB 資料表,皆不得包含被外部鍵參照的欄位。

上述限制的範圍包括所有使用 InnoDB 儲存引擎的資料表。任何會導致資料表違反這些限制的 CREATE TABLEALTER TABLE 陳述均不允許。

ALTER TABLE ... ORDER BY。 對於分割資料表執行的 ALTER TABLE ... ORDER BY column 陳述,只會排序每個分割區內的列。

ADD COLUMN ... ALGORITHM=INSTANT。 一旦對分割資料表執行 ALTER TABLE ... ADD COLUMN ... ALGORITHM=INSTANT,就無法再與該資料表交換分割區。

透過修改主鍵對 REPLACE 陳述的影響。 在某些情況下,修改資料表的主鍵是可取的(請參閱第 26.6.1 節,「分割鍵、主鍵和唯一鍵」)。請注意,如果您的應用程式使用 REPLACE 陳述,且您這麼做,這些陳述的結果可能會被大幅更改。請參閱 第 15.2.12 節,「REPLACE 陳述」,以取得更多資訊和範例。

FULLTEXT 索引。 分割資料表不支援 FULLTEXT 索引或搜尋。

空間欄位。 具有空間資料類型(例如 POINTGEOMETRY)的欄位不能用於分割資料表。

暫存資料表。 暫存資料表無法分割。

日誌資料表。 無法分割日誌資料表;對此類資料表執行 ALTER TABLE ... PARTITION BY ... 陳述會失敗並顯示錯誤。

分割鍵的資料類型。 分割鍵必須是整數欄位或解析為整數的運算式。使用 ENUM 欄位的運算式不能使用。欄位或運算式值也可以是 NULL;請參閱第 26.2.7 節,「MySQL 分割如何處理 NULL」

此限制有兩個例外情況:

  1. 當按 [LINEAR] KEY 分割時,可以使用任何有效的 MySQL 資料類型(除了 TEXTBLOB 之外)的欄位作為分割鍵,因為內部金鑰雜湊函數會從這些類型產生正確的資料類型。例如,以下兩個 CREATE TABLE 陳述是有效的:

    CREATE TABLE tkc (c1 CHAR)
    PARTITION BY KEY(c1)
    PARTITIONS 4;
    
    CREATE TABLE tke
        ( c1 ENUM('red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet') )
    PARTITION BY LINEAR KEY(c1)
    PARTITIONS 6;
  2. 當按 RANGE COLUMNSLIST COLUMNS 分割時,可以使用字串、DATEDATETIME 欄位。例如,以下每個 CREATE TABLE 陳述都是有效的:

    CREATE TABLE rc (c1 INT, c2 DATE)
    PARTITION BY RANGE COLUMNS(c2) (
        PARTITION p0 VALUES LESS THAN('1990-01-01'),
        PARTITION p1 VALUES LESS THAN('1995-01-01'),
        PARTITION p2 VALUES LESS THAN('2000-01-01'),
        PARTITION p3 VALUES LESS THAN('2005-01-01'),
        PARTITION p4 VALUES LESS THAN(MAXVALUE)
    );
    
    CREATE TABLE lc (c1 INT, c2 CHAR(1))
    PARTITION BY LIST COLUMNS(c2) (
        PARTITION p0 VALUES IN('a', 'd', 'g', 'j', 'm', 'p', 's', 'v', 'y'),
        PARTITION p1 VALUES IN('b', 'e', 'h', 'k', 'n', 'q', 't', 'w', 'z'),
        PARTITION p2 VALUES IN('c', 'f', 'i', 'l', 'o', 'r', 'u', 'x', NULL)
    );

上述任何例外情況都不適用於 BLOBTEXT 欄位類型。

子查詢。 分割鍵不得為子查詢,即使該子查詢解析為整數值或 NULL

金鑰分割不支援欄位索引前綴。 建立按金鑰分割的資料表時,在資料表分割函數中不允許使用任何使用欄位前綴的分割鍵中的欄位。請考慮以下 CREATE TABLE 陳述,其中有三個 VARCHAR 欄位,並且其主鍵使用所有三個欄位,並為其中一個指定前綴。此陳述會被拒絕,並顯示錯誤,如下所示:

mysql> USE d;
Database changed
mysql> CREATE TABLE t1 (
    ->     a VARCHAR(10000),
    ->     b VARCHAR(25),
    ->     c VARCHAR(10),
    ->     PRIMARY KEY (a(10), b, c)
    -> ) PARTITION BY KEY() PARTITIONS 2;
ERROR 6123 (HY000): Column 'd.t1.a' having prefix key part 'a(10)' in the
PARTITION BY KEY() clause is not supported.

有關按金鑰分割資料表的一般資訊,請參閱第 26.2.5 節,「金鑰分割」

子分割的問題。 子分割必須使用 HASHKEY 分割。只有 RANGELIST 分割可以進行子分割;HASHKEY 分割無法進行子分割。

SUBPARTITION BY KEY 要求明確指定子分割欄位或多個欄位,這與 PARTITION BY KEY 的情況不同,後者可以省略(在這種情況下,預設會使用資料表的主鍵欄位)。請考慮由此陳述建立的資料表:

CREATE TABLE ts (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(30)
);

您可以使用類似以下陳述來建立具有相同欄位、按 KEY 分割的資料表:

CREATE TABLE ts (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(30)
)
PARTITION BY KEY()
PARTITIONS 4;

先前的陳述被視為好像是這樣寫的,使用資料表的主鍵欄位作為分割欄位:

CREATE TABLE ts (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(30)
)
PARTITION BY KEY(id)
PARTITIONS 4;

但是,嘗試使用預設欄位作為子分割欄位來建立子分割資料表的以下陳述會失敗,並且必須為該陳述指定欄位才能成功,如下所示:

mysql> CREATE TABLE ts (
    ->     id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->     name VARCHAR(30)
    -> )
    -> PARTITION BY RANGE(id)
    -> SUBPARTITION BY KEY()
    -> SUBPARTITIONS 4
    -> (
    ->     PARTITION p0 VALUES LESS THAN (100),
    ->     PARTITION p1 VALUES LESS THAN (MAXVALUE)
    -> );
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near ')

mysql> CREATE TABLE ts (
    ->     id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    ->     name VARCHAR(30)
    -> )
    -> PARTITION BY RANGE(id)
    -> SUBPARTITION BY KEY(id)
    -> SUBPARTITIONS 4
    -> (
    ->     PARTITION p0 VALUES LESS THAN (100),
    ->     PARTITION p1 VALUES LESS THAN (MAXVALUE)
    -> );
Query OK, 0 rows affected (0.07 sec)

這是一個已知問題(請參閱錯誤 #51470)。

DATA DIRECTORY 和 INDEX DIRECTORY 選項。 資料表層級的 DATA DIRECTORYINDEX DIRECTORY 選項會被忽略(請參閱錯誤 #32091)。您可以將這些選項用於 InnoDB 資料表的個別分割區或子分割區。DATA DIRECTORY 子句中指定的目錄必須為 InnoDB 所知。如需更多資訊,請參閱「使用 DATA DIRECTORY 子句」

修復和重建分割資料表。 分割資料表支援 CHECK TABLEOPTIMIZE TABLEANALYZE TABLEREPAIR TABLE 陳述。

此外,您可以使用 ALTER TABLE ... REBUILD PARTITION 來重建分割資料表的一個或多個分割區;ALTER TABLE ... REORGANIZE PARTITION 也會導致分割區重建。有關這兩個陳述的更多資訊,請參閱第 15.1.9 節,「ALTER TABLE 陳述」

子分割支援 ANALYZECHECKOPTIMIZEREPAIRTRUNCATE 操作。請參閱第 15.1.9.1 節,「ALTER TABLE 分割操作」

分割區和子分割區的檔案名稱分隔符號。 資料表分割區和子分割區檔案名稱包含產生的分隔符號,例如 #P##SP#。此類分隔符號的大小寫可能會有所不同,不應依賴。