MySQL 9.0 參考手冊  /  ...  /  HASH 分割區

26.2.4 HASH 分割區

使用 HASH 進行分割主要是為了確保資料在預先決定的分割區數量之間均勻分佈。使用範圍或列表分割區,您必須明確指定給定的欄位值或一組欄位值應儲存在哪個分割區中;使用雜湊分割區,此決定會自動為您處理,您只需要指定一個欄位值或基於欄位值的運算式來進行雜湊運算,以及分割表格將要分割成的分割區數量。

若要使用 HASH 分割來分割表格,必須在 CREATE TABLE 陳述式中附加 PARTITION BY HASH (expr) 子句,其中 expr 是一個傳回整數的運算式。這可以只是類型為 MySQL 整數類型之一的欄位名稱。此外,您很可能希望在此之後加上 PARTITIONS num,其中 num 是一個正整數,表示表格將要分割成的分割區數量。

注意

為了簡單起見,以下範例中的表格未使用任何索引鍵。您應該知道,如果表格有任何唯一索引鍵,則用於此表格分割運算式中的每個欄位都必須是每個唯一索引鍵的一部分,包括主索引鍵。請參閱 第 26.6.1 節,「分割區索引鍵、主索引鍵和唯一索引鍵」,以取得更多資訊。

以下陳述式會建立一個表格,該表格在 store_id 欄位上使用雜湊,並分為 4 個分割區

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 HASH(store_id)
PARTITIONS 4;

如果您不包含 PARTITIONS 子句,則分割區數量預設為 1;使用 PARTITIONS 關鍵字而沒有後續數字會導致語法錯誤。

您也可以使用傳回整數的 SQL 運算式作為 expr。例如,您可能想要根據員工受僱的年份進行分割。這可以透過如下方式完成

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 HASH( YEAR(hired) )
PARTITIONS 4;

expr 必須傳回一個非常數、非隨機整數值(換句話說,它應該是變化的但確定的),並且不得包含 第 26.6 節,「分割區的限制」中描述的任何禁止的結構。您還應該記住,每次插入或更新(或可能刪除)一列時,都會評估此運算式;這表示非常複雜的運算式可能會產生效能問題,尤其是在執行一次影響大量列的作業(例如批次插入)時。

最有效的雜湊函數是在單一表格欄位上操作,且其值會隨著欄位值一致地增加或減少,因為這允許對分割區範圍進行 修剪。也就是說,運算式與其所根據的欄位值變化越密切,MySQL 就能越有效率地將運算式用於雜湊分割區。

例如,其中 date_colDATE 類型的欄位,則運算式 TO_DAYS(date_col) 被認為與 date_col 的值直接變化,因為對於 date_col 值的每次變更,運算式的值都會以一致的方式變更。運算式 YEAR(date_col) 相對於 date_col 的變化不像 TO_DAYS(date_col) 那麼直接,因為並非 date_col 中每個可能的變更都會在 YEAR(date_col) 中產生對等的變更。即便如此,YEAR(date_col) 仍然是雜湊函數的良好候選者,因為它與 date_col 的一部分直接變化,而且 date_col 中沒有可能產生 YEAR(date_col) 中不成比例變更的變更。

相比之下,假設您有一個名為 int_col 的欄位,其類型為 INT。現在考慮運算式 POW(5-int_col,3) + 6。這對於雜湊函數來說會是一個很差的選擇,因為無法保證 int_col 值的變更會在運算式的值中產生比例變更。將 int_col 的值變更給定的數量可能會在運算式的值中產生差異很大的變更。例如,將 int_col5 變更為 6 會使運算式的值變更 -1,但是將 int_col 的值從 6 變更為 7 會使運算式的值變更 -7

換句話說,欄位值與運算式值的圖表越接近方程 y=cx 所繪製的直線,其中 c 是一些非零常數,則運算式就越適合雜湊。這與以下事實有關:運算式越非線性,它傾向於產生資料在分割區之間的分佈越不均勻。

理論上,對於涉及多個欄位值的運算式,也可以進行修剪,但是確定哪些此類運算式是合適的可能非常困難且耗時。因此,不特別建議使用涉及多個欄位的雜湊運算式。

當使用 PARTITION BY HASH 時,儲存引擎會根據運算式結果的模數來決定使用 num 個分割區中的哪個分割區。換句話說,對於給定的運算式 expr,儲存記錄的分割區是分割區編號 N,其中 N = MOD(expr, num)。假設表格 t1 定義如下,以便它有 4 個分割區

CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE)
    PARTITION BY HASH( YEAR(col3) )
    PARTITIONS 4;

如果您將一筆 col3 值為 '2005-09-15' 的記錄插入到 t1 中,則會以下列方式決定其儲存的分割區

MOD(YEAR('2005-09-01'),4)
=  MOD(2005,4)
=  1

MySQL 9.0 還支援 HASH 分割的一種變體,稱為線性雜湊,它採用更複雜的演算法來確定插入到分割表格中的新列的放置位置。有關此演算法的描述,請參閱 第 26.2.4.1 節,「LINEAR HASH 分割區」

每次插入或更新記錄時,都會評估使用者提供的運算式。在某些情況下,也可能會在刪除記錄時評估。