MySQL 9.0 參考手冊  /  ...  /  RANGE 分割

26.2.1 RANGE 分割

依範圍分割的表格,其分割方式是使每個分割區包含分割運算式值落在指定範圍內的列。範圍應為連續但不重疊,並使用 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。)

當符合下列一或多個條件時,範圍分割特別有用

此類分割的一種變體是 RANGE COLUMNS 分割。透過 RANGE COLUMNS 進行分割可以採用多個欄位來定義分割範圍,這些範圍既適用於將列放置在分割區中,也適用於在執行分割區修剪時判斷是否包含或排除特定分割區。有關更多資訊,請參閱第 26.2.3.1 節,「RANGE COLUMNS 分割」

基於時間間隔的分割配置。如果您希望在 MySQL 9.0 中實施基於時間範圍或間隔的分割配置,您有兩種選擇

  1. RANGE 分割表格,並針對分割表示式,採用對 DATETIMEDATETIME 欄位進行運算並傳回整數值的函式,如此處所示

    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) 用作分割表示式。但是,通常不建議這樣做。

  2. 使用 DATEDATETIME 欄位作為分割欄位,依 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
    );
注意

使用 DATEDATETIME 類型以外的日期或時間類型的分割欄位,在 RANGE COLUMNS 中不受支援。