依範圍分割的表格,會以每個分割區包含分割區運算式值落在給定範圍內的方式進行分割。範圍應該是連續的,但不應該重疊,並使用 VALUES LESS THAN
運算子定義。在接下來的幾個範例中,假設您正在建立如下的表格,以保存 20 家連鎖影音商店(編號 1 到 20)的人事記錄
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
);
此處使用的 employees
表格沒有主鍵或唯一鍵。雖然範例為了目前的討論目的而如所示地運作,但您應該記住,實際上表格極有可能會有主鍵、唯一鍵或兩者都有,而且分割區欄位的允許選項取決於這些鍵所使用的欄位(如果有的話)。有關這些問題的討論,請參閱 第 26.6.1 節「分割區鍵、主鍵和唯一鍵」。
此表格可以根據您的需求以多種方式依範圍進行分割。一種方法是使用 store_id
欄位。例如,您可能會決定將表格分割為 4 個部分,方法是新增如下所示的 PARTITION BY RANGE
子句
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
PARTITION p0 VALUES LESS THAN (6),
PARTITION p1 VALUES LESS THAN (11),
PARTITION p2 VALUES LESS THAN (16),
PARTITION p3 VALUES LESS THAN (21)
);
在這個分割區配置中,所有對應於在商店 1 到 5 工作的員工的列都儲存在分割區 p0
中,對應於在商店 6 到 10 工作的員工的列都儲存在分割區 p1
中,依此類推。每個分割區都會按順序由最低到最高定義。這是 PARTITION BY RANGE
語法的要求;您可以把它想成是 C 或 Java 中一系列 if ... elseif ...
陳述式的類比。
很容易確定包含資料 (72, 'Mitchell', 'Wilson', '1998-06-25', DEFAULT, 7, 13)
的新列會插入到分割區 p2
中,但是當您的連鎖店新增第 21 間商店時會發生什麼事?在這個配置下,沒有規則涵蓋 store_id
大於 20 的列,因此會產生錯誤,因為伺服器不知道要將它放在哪裡。您可以透過在 CREATE TABLE
陳述式中使用 「catchall」 VALUES LESS THAN
子句來防止這種情況發生,此子句會處理所有大於明確命名的最高值的值
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
PARTITION p0 VALUES LESS THAN (6),
PARTITION p1 VALUES LESS THAN (11),
PARTITION p2 VALUES LESS THAN (16),
PARTITION p3 VALUES LESS THAN MAXVALUE
);
(如同本章的其他範例,我們假設預設儲存引擎是 InnoDB
。)
避免找不到相符值時發生錯誤的另一種方法,是在 INSERT
陳述式中使用 IGNORE
關鍵字作為一部分。如需範例,請參閱 第 26.2.2 節「LIST 分割區」。
MAXVALUE
表示一個整數值,它永遠大於可能的最大整數值(在數學語言中,它充當最小上限)。現在,任何 store_id
欄位值大於或等於 16(定義的最高值)的列都會儲存在分割區 p3
中。在未來的某個時候 — 當商店數量增加到 25 間、30 間或更多時 — 您可以使用 ALTER TABLE
陳述式來為商店 21-25、26-30 等新增分割區(如需如何執行此操作的詳細資訊,請參閱第 26.3 節「分割區管理」)。
以幾乎相同的方式,您可以根據員工職位代碼(也就是根據 job_code
欄位值的範圍)來分割表格。例如 — 假設兩位數的職位代碼用於一般(店內)員工、三位數的代碼用於辦公室和支援人員,而四位數的代碼用於管理職位 — 您可以使用下列陳述式來建立分割的表格
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT NOT NULL,
store_id INT NOT NULL
)
PARTITION BY RANGE (job_code) (
PARTITION p0 VALUES LESS THAN (100),
PARTITION p1 VALUES LESS THAN (1000),
PARTITION p2 VALUES LESS THAN (10000)
);
在這個範例中,所有與店內員工相關的列都會儲存在分割區 p0
中,與辦公室和支援人員相關的列會儲存在 p1
中,與經理相關的列會儲存在分割區 p2
中。
也可以在 VALUES LESS THAN
子句中使用運算式。但是,MySQL 必須能夠評估運算式的傳回值,以作為 LESS THAN
(<
) 比較的一部分。
您可以不根據商店編號來分割表格資料,而是改用基於兩個 DATE
欄位之一的運算式。例如,假設您希望根據每位員工離開公司的年份(也就是 YEAR(separated)
的值)來進行分割。以下顯示實作此分割區配置的 CREATE TABLE
陳述式範例
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated DATE NOT NULL DEFAULT '9999-12-31',
job_code INT,
store_id INT
)
PARTITION BY RANGE ( YEAR(separated) ) (
PARTITION p0 VALUES LESS THAN (1991),
PARTITION p1 VALUES LESS THAN (1996),
PARTITION p2 VALUES LESS THAN (2001),
PARTITION p3 VALUES LESS THAN MAXVALUE
);
在這個配置中,對於所有在 1991 年之前離開的員工,列都儲存在分割區 p0
中;對於在 1991 年到 1995 年之間離開的員工,則儲存在 p1
中;對於在 1996 年到 2000 年之間離開的員工,則儲存在 p2
中;對於在 2000 年之後離開的任何員工,則儲存在 p3
中。
也可以根據 TIMESTAMP
欄位的值,使用 UNIX_TIMESTAMP()
函式,依據 RANGE
來分割表格,如下列範例所示
CREATE TABLE quarterly_report_status (
report_id INT NOT NULL,
report_status VARCHAR(20) NOT NULL,
report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)
PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) (
PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
PARTITION p9 VALUES LESS THAN (MAXVALUE)
);
不允許任何其他涉及 TIMESTAMP
值的運算式。(請參閱錯誤 #42849。)
當符合下列一或多個條件時,範圍分割區特別有用
您想要或需要刪除「舊的」資料。如果您使用先前顯示的
employees
表格的分割區配置,您可以直接使用ALTER TABLE employees DROP PARTITION p0;
來刪除所有與 1991 年之前停止為公司工作的員工相關的列。(如需更多資訊,請參閱 第 15.1.9 節「ALTER TABLE 陳述式」和 第 26.3 節「分割區管理」。)對於具有大量列的表格,這會比執行DELETE
查詢(例如DELETE FROM employees WHERE YEAR(separated) <= 1990;
)更有效率。您想要使用包含日期或時間值的欄位,或包含來自其他某些序列的值。
您經常執行的查詢會直接依賴用於分割表格的欄位。例如,當執行如下查詢時:
EXPLAIN SELECT COUNT(*) FROM employees WHERE separated BETWEEN '2000-01-01' AND '2000-12-31' GROUP BY store_id;
,MySQL 可以快速確定只需要掃描分割區p2
,因為其餘的分割區不包含任何滿足WHERE
子句的記錄。有關如何實現此操作的更多資訊,請參閱第 26.4 節「分割區修剪」。
此類分割的變體是 RANGE COLUMNS
分割。使用 RANGE COLUMNS
進行分割使得可以使用多個欄位來定義分割範圍,這些範圍同時適用於將行放置在分割區中,以及在執行分割區修剪時確定是否包含或排除特定分割區。有關更多資訊,請參閱第 26.2.3.1 節「RANGE COLUMNS 分割」。
基於時間間隔的分割方案。如果您希望在 MySQL 8.4 中實施基於時間範圍或間隔的分割方案,您有兩個選項
依
RANGE
分割表格,並將函數應用於DATE
、TIME
或DATETIME
欄位並返回整數值的函式,作為分割表達式,如下所示CREATE TABLE members ( firstname VARCHAR(25) NOT NULL, lastname VARCHAR(25) NOT NULL, username VARCHAR(16) NOT NULL, email VARCHAR(35), joined DATE NOT NULL ) PARTITION BY RANGE( YEAR(joined) ) ( PARTITION p0 VALUES LESS THAN (1960), PARTITION p1 VALUES LESS THAN (1970), PARTITION p2 VALUES LESS THAN (1980), PARTITION p3 VALUES LESS THAN (1990), PARTITION p4 VALUES LESS THAN MAXVALUE );
在 MySQL 8.4 中,也可以使用
UNIX_TIMESTAMP()
函數,根據TIMESTAMP
欄位的值,依RANGE
分割表格,如以下範例所示CREATE TABLE quarterly_report_status ( report_id INT NOT NULL, report_status VARCHAR(20) NOT NULL, report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) ( PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ), PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ), PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ), PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ), PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ), PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ), PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ), PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ), PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ), PARTITION p9 VALUES LESS THAN (MAXVALUE) );
在 MySQL 8.4 中,任何其他涉及
TIMESTAMP
值的表達式都是不允許的。(請參閱錯誤 #42849。)注意在 MySQL 8.4 中,也可以使用
UNIX_TIMESTAMP(timestamp_column)
作為依LIST
分割的表格的分割表達式。但是,這樣做通常不切實際。使用
DATE
或DATETIME
欄位作為分割欄位,依RANGE COLUMNS
分割表格。例如,可以使用joined
欄位直接定義members
表格,如下所示CREATE TABLE members ( firstname VARCHAR(25) NOT NULL, lastname VARCHAR(25) NOT NULL, username VARCHAR(16) NOT NULL, email VARCHAR(35), joined DATE NOT NULL ) PARTITION BY RANGE COLUMNS(joined) ( PARTITION p0 VALUES LESS THAN ('1960-01-01'), PARTITION p1 VALUES LESS THAN ('1970-01-01'), PARTITION p2 VALUES LESS THAN ('1980-01-01'), PARTITION p3 VALUES LESS THAN ('1990-01-01'), PARTITION p4 VALUES LESS THAN MAXVALUE );
使用 DATE
或 DATETIME
以外的日期或時間類型的分割欄位,RANGE COLUMNS
不支援。