MySQL 9.0 參考手冊  /  分割  /  分割的限制與約束

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 9.0 中,LOAD DATA 使用緩衝來改善效能。您應該注意到,緩衝區會使用每個分割區 130 KB 的記憶體來達到此目的。

分割的最大數目。  未使用 NDB 儲存引擎的指定資料表,其最大可能分割區數目為 8192 個。此數目包括子分割區。

使用 NDB 儲存引擎的資料表,其最大可能使用者定義分割區數目是根據正在使用的 NDB Cluster 軟體版本、資料節點數目和其他因素決定。請參閱 NDB 和使用者定義的分割,以取得更多資訊。

如果您在建立具有大量分割區 (但少於最大值) 的資料表時遇到類似 Got error ... from storage engine: Out of resources when opening file 的錯誤訊息,您或許可以藉由增加 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 分割時,可以使用除了 TEXTBLOB 以外的任何有效 MySQL 資料類型欄位作為分割鍵,因為內部金鑰雜湊函數會從這些類型產生正確的資料類型。例如,以下兩個 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#。這些分隔符號的字母大小寫可能會有所不同,不應依賴其大小寫。