MySQL 8.4 參考手冊  /  ...  /  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 陳述式中使用 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。)

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

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

基於時間間隔的分割方案。如果您希望在 MySQL 8.4 中實施基於時間範圍或間隔的分割方案,您有兩個選項

  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 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 分割的表格的分割表達式。但是,這樣做通常不切實際。

  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 不支援。