依範圍分割的表格,其分割方式是使每個分割區包含分割運算式值落在指定範圍內的列。範圍應為連續但不重疊,並使用 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
陳述式中包含一個 「全包」 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 9.0 中實施基於時間範圍或間隔的分割配置,您有兩種選擇
依
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 9.0 中,也可以基於
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) );
在 MySQL 9.0 中,不允許使用任何其他涉及
TIMESTAMP
值的表示式。(請參閱錯誤 #42849。)注意在 MySQL 9.0 中,也可以針對依
LIST
分割的表格,將UNIX_TIMESTAMP(timestamp_column)
用作分割表示式。但是,通常不建議這樣做。使用
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
中不受支援。