稱為 分區修剪 的最佳化基於一個相對簡單的概念,可以描述為 「不掃描任何不包含符合值的分割區」。假設一個分割資料表 t1
是使用此陳述式建立的
CREATE TABLE t1 (
fname VARCHAR(50) NOT NULL,
lname VARCHAR(50) NOT NULL,
region_code TINYINT UNSIGNED NOT NULL,
dob DATE NOT NULL
)
PARTITION BY RANGE( region_code ) (
PARTITION p0 VALUES LESS THAN (64),
PARTITION p1 VALUES LESS THAN (128),
PARTITION p2 VALUES LESS THAN (192),
PARTITION p3 VALUES LESS THAN MAXVALUE
);
假設您希望從一個 SELECT
陳述式中取得結果,例如以下這個陳述式
SELECT fname, lname, region_code, dob
FROM t1
WHERE region_code > 125 AND region_code < 130;
很容易看出,任何應該傳回的資料列都不在分割區 p0
或 p3
中;也就是說,我們只需要搜尋分割區 p1
和 p2
即可找到相符的資料列。藉由限制搜尋,在尋找相符資料列時,可以花費比掃描表格中的所有分割區少得多的時間和精力。這種 「剪除」不需要的分割區的行為稱為 修剪。當最佳化工具可以在執行此查詢時利用分區修剪時,查詢的執行速度可以比針對包含相同欄定義和資料的未分割資料表執行相同查詢快一個數量級。
當 WHERE
條件可以簡化為以下兩種情況之一時,最佳化工具可以執行修剪
partition_column
=constant
partition_column
IN (constant1
,constant2
, ...,constantN
)
在第一種情況下,最佳化工具只需針對給定的值評估分區運算式,判斷哪個分割區包含該值,並且只掃描此分割區。在許多情況下,等號可以替換為另一個算術比較,包括 <
、>
、<=
、>=
和 <>
。在 WHERE
子句中使用 BETWEEN
的某些查詢也可以利用分區修剪。請參閱本節稍後的範例。
在第二種情況下,最佳化工具會評估清單中每個值的分區運算式,建立相符分割區的清單,然後只掃描此分割區清單中的分割區。
SELECT
、DELETE
和 UPDATE
陳述式支援分區修剪。INSERT
陳述式也會針對每個插入的資料列只存取一個分割區;即使表格是依照 HASH
或 KEY
分割的,也是如此,儘管這目前未顯示在 EXPLAIN
的輸出中。
修剪也可以應用於短範圍,最佳化工具可以將其轉換為等效的值清單。例如,在先前的範例中,WHERE
子句可以轉換為 WHERE region_code IN (126, 127, 128, 129)
。然後最佳化工具可以判斷清單中的前兩個值在分割區 p1
中找到,剩餘的兩個值在分割區 p2
中找到,而其他分割區不包含相關的值,因此不需要搜尋相符的資料列。
對於使用 RANGE COLUMNS
或 LIST COLUMNS
分割的表格,如果 WHERE
條件包含先前類型在多個欄位上的比較,則最佳化工具也可以執行修剪。
只要分割運算式包含可以簡化為一組等式的等式或範圍,或者當分割運算式表示遞增或遞減關係時,就可以應用此類型的最佳化。當分割運算式使用 YEAR()
或 TO_DAYS()
函式時,也可以針對在 DATE
或 DATETIME
欄位上分割的表格執行修剪。當分割運算式使用 TO_SECONDS()
函式時,也可以針對此類表格執行修剪。
假設使用此處所示的陳述式建立一個在 DATE
欄位上分割的表格 t2
CREATE TABLE t2 (
fname VARCHAR(50) NOT NULL,
lname VARCHAR(50) NOT NULL,
region_code TINYINT UNSIGNED NOT NULL,
dob DATE NOT NULL
)
PARTITION BY RANGE( YEAR(dob) ) (
PARTITION d0 VALUES LESS THAN (1970),
PARTITION d1 VALUES LESS THAN (1975),
PARTITION d2 VALUES LESS THAN (1980),
PARTITION d3 VALUES LESS THAN (1985),
PARTITION d4 VALUES LESS THAN (1990),
PARTITION d5 VALUES LESS THAN (2000),
PARTITION d6 VALUES LESS THAN (2005),
PARTITION d7 VALUES LESS THAN MAXVALUE
);
下列使用 t2
的陳述式可以使用分區修剪
SELECT * FROM t2 WHERE dob = '1982-06-23';
UPDATE t2 SET region_code = 8 WHERE dob BETWEEN '1991-02-15' AND '1997-04-25';
DELETE FROM t2 WHERE dob >= '1984-06-21' AND dob <= '1999-06-21'
在最後一個陳述式的情況下,最佳化工具也可以執行下列動作
尋找包含範圍低端的分割區.
YEAR('1984-06-21')
產生值1984
,此值在分割區d3
中找到。尋找包含範圍高端的分割區.
YEAR('1999-06-21')
評估為1999
,此值在分割區d5
中找到。只掃描這兩個分割區以及可能位於它們之間的任何分割區.
在此情況下,這表示只會掃描分割區
d3
、d4
和d5
。可以安全地忽略(並且確實忽略)其餘分割區。
在針對分割表格的陳述式的 WHERE
條件中參照的無效 DATE
和 DATETIME
值會被視為 NULL
。這表示像 SELECT * FROM
這樣的查詢不會傳回任何值(請參閱錯誤 #40972)。partitioned_table
WHERE date_column
< '2008-12-00'
到目前為止,我們只看過使用 RANGE
分割的範例,但修剪也可以應用於其他分割類型。
考量一個依照 LIST
分割的表格,其中分割運算式是遞增或遞減的,例如此處顯示的表格 t3
。(在此範例中,為了簡潔起見,我們假設 region_code
欄位的值限制在 1 到 10(含)之間。)
CREATE TABLE t3 (
fname VARCHAR(50) NOT NULL,
lname VARCHAR(50) NOT NULL,
region_code TINYINT UNSIGNED NOT NULL,
dob DATE NOT NULL
)
PARTITION BY LIST(region_code) (
PARTITION r0 VALUES IN (1, 3),
PARTITION r1 VALUES IN (2, 5, 8),
PARTITION r2 VALUES IN (4, 9),
PARTITION r3 VALUES IN (6, 7, 10)
);
對於像 SELECT * FROM t3 WHERE region_code BETWEEN 1 AND 3
這樣的陳述式,最佳化工具會判斷在哪些分割區中找到值 1、2 和 3(r0
和 r1
),並跳過其餘分割區(r2
和 r3
)。
對於使用 HASH
或 [LINEAR] KEY
進行分割的表格,當 WHERE
子句中使用針對分割表示式中所用欄位的簡單 =
關係時,也可以進行分割修剪。考慮如下建立的表格
CREATE TABLE t4 (
fname VARCHAR(50) NOT NULL,
lname VARCHAR(50) NOT NULL,
region_code TINYINT UNSIGNED NOT NULL,
dob DATE NOT NULL
)
PARTITION BY KEY(region_code)
PARTITIONS 8;
比較欄位值與常數的陳述式可以被修剪
UPDATE t4 WHERE region_code = 7;
修剪也可以用於短範圍,因為最佳化工具可以將此類條件轉換為 IN
關係。例如,使用先前定義的相同表格 t4
,諸如此類的查詢可以被修剪
SELECT * FROM t4 WHERE region_code > 2 AND region_code < 6;
SELECT * FROM t4 WHERE region_code BETWEEN 3 AND 5;
在這兩種情況下,WHERE
子句都會被最佳化工具轉換為 WHERE region_code IN (3, 4, 5)
。
只有在範圍大小小於分割區數量時,才會使用此最佳化。考慮以下陳述式
DELETE FROM t4 WHERE region_code BETWEEN 4 AND 12;
WHERE
子句中的範圍涵蓋 9 個值(4、5、6、7、8、9、10、11、12),但 t4
只有 8 個分割區。這表示無法修剪 DELETE
。
當表格使用 HASH
或 [LINEAR] KEY
進行分割時,修剪只能用於整數欄位。例如,由於 dob
是 DATE
欄位,因此此陳述式無法使用修剪
SELECT * FROM t4 WHERE dob >= '2001-04-14' AND dob <= '2005-10-15';
但是,如果表格在 INT
欄位中儲存年份值,則具有 WHERE year_col >= 2001 AND year_col <= 2005
的查詢可以被修剪。
使用提供自動分割的儲存引擎的表格(例如 MySQL Cluster 使用的 NDB
儲存引擎),如果它們被明確分割,則可以被修剪。