全部產品
Search
文件中心

PolarDB:線上分區維護

更新時間:Jul 06, 2024

本文檔主要介紹了PolarDB的線上分區維護功能。

在MySQL社區版中,對分區表資料的訪問操作(DML)與分區維護操作(DDL)是相互阻塞的,這使得分區維護操作只能在業務低峰時段進行。而對分區表進行建立和刪除分區操作是比較頻繁的,這極大限制了分區表的使用。線上分區維護功能增強了分區的DML和特定DDL(增加、刪除分區)的並行能力,更好的讓使用者對分區表進行Roll-In和Roll-Out。如下圖所示:分區鎖

前提條件

  • 叢集版本需為PolarDB MySQL版8.0版本且Revision version為8.0.2.2.0及以上。您可以通過查詢版本號碼確認叢集版本。

  • 已經開啟partition_level_mdl_enabled參數。具體操作請參見設定叢集參數和節點參數

    參數名稱

    層級

    參數說明

    partition_level_mdl_enabled

    Global

    PARTITION Level MDL功能開關,取值範圍如下:

    • ON:開啟PARTITION Level MDL功能

    • OFF:關閉PARTITION Level MDL功能

    說明

    修改該參數需要重啟叢集。

  • transaction_isolation參數的全域隔離等級需要設定為READ-COMMITTED。具體操作請參見設定叢集參數和節點參數

使用限制

  • 目前支援DROP/EXCHANGE/REBUILD/REORGANIZE PARTITION操作、RANGE和LIST分區方式的ADD PARTITION操作的線上分區維護功能,其他DDL操作將在後續版本支援。

  • 由於隔離等級可以設定為session層級,如果transaction-isolation設定為REPEATABLE-READ或者更強的隔離等級,在並發執行DDL過程中,可能會報錯ERROR HY000: Table definition has changed, please retry transaction,這屬於正常現象。原因是事務訪問到了DDL所建立出來的新分區,可通過重新執行事務解決。

使用說明及樣本

線上分區維護功能,使得分區表的資料訪問和分區維護相互不影響,使用者可以更自由的進行分區維護,而不影響分區表業務流量,使用樣本及效果如下:

#在用戶端1上輸出tr表結構
SHOW CREATE TABLE tr\G                                 
*************************** 1. row ***************************    
       Table: tr                                                  
Create Table: CREATE TABLE `tr` (                                  
  `id` int(11) DEFAULT NULL,                                       
  `name` varchar(50) DEFAULT NULL,                                 
  `purchased` date DEFAULT NULL                                    
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 
/*!50100 PARTITION BY RANGE (year(`purchased`))                    
(PARTITION p0 VALUES LESS THAN (1990) ENGINE = InnoDB,             
 PARTITION p1 VALUES LESS THAN (1995) ENGINE = InnoDB,             
 PARTITION p2 VALUES LESS THAN (2000) ENGINE = InnoDB,             
 PARTITION p3 VALUES LESS THAN (2005) ENGINE = InnoDB,            
 PARTITION p4 VALUES LESS THAN (2010) ENGINE = InnoDB,            
 PARTITION p5 VALUES LESS THAN (2015) ENGINE = InnoDB) */         
1 row in set (0.00 sec)

#在用戶端1上開啟事務
BEGIN;                                                 
Query OK, 0 rows affected (0.01 sec)                               
                                                                  
SELECT * FROM tr WHERE purchased >= '2010-01-01';      
+------+----------------+------------+                            
| id   | name           | purchased  |                             
+------+----------------+------------+                             
|    5 | exercise bike  | 2014-05-09 |                         
|    7 | espresso maker | 2011-11-22 |                             
+------+----------------+------------+                             
2 rows in set (0.01 sec)                                          

#在用戶端2上建立新分區
ALTER TABLE tr ADD PARTITION (PARTITION p6 VALUES LESS THAN (2020));
INSERT INTO tr VALUES (11, 'hope', '2017-11-04'), (12, 'carmen', '2018-06-08');

#在同一個事務內,通過用戶端1可以訪問到新增分區的資料
SELECT * FROM tr WHERE purchased >= '2010-01-01';
+------+----------------+------------+                             
| id   | name           | purchased  |                            
+------+----------------+------------+                            
|    5 | exercise bike  | 2014-05-09 |                            
|    7 | espresso maker | 2011-11-22 |                             
|   11 | hope           | 2017-11-04 |                             
|   12 | carmen         | 2018-06-08 |                            
+------+----------------+------------+                            
4 rows in set (0.00 sec)

#在用戶端2上刪除舊分區
ALTER TABLE tr DROP PARTITION p0;

#在用戶端1上輸出表定義,可以看到新分區p6存在,舊分區p0已不存在
SHOW CREATE TABLE tr\G                                 
*************************** 1. row ***************************     
       Table: tr                                                   
Create Table: CREATE TABLE `tr` (                                 
  `id` int(11) DEFAULT NULL,                                       
  `name` varchar(50) DEFAULT NULL,                                 
  `purchased` date DEFAULT NULL                                    
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 
/*!50100 PARTITION BY RANGE (year(`purchased`))                    
(PARTITION p1 VALUES LESS THAN (1995) ENGINE = InnoDB,             
 PARTITION p2 VALUES LESS THAN (2000) ENGINE = InnoDB,             
 PARTITION p3 VALUES LESS THAN (2005) ENGINE = InnoDB,             
 PARTITION p4 VALUES LESS THAN (2010) ENGINE = InnoDB,            
 PARTITION p5 VALUES LESS THAN (2015) ENGINE = InnoDB,             
 PARTITION p6 VALUES LESS THAN (2020) ENGINE = InnoDB) */         
1 row in set (0.00 sec)

#在用戶端1上提交事務
COMMIT;

效能表現

下面針對DML和DDL互動下的兩種最主要情境長事務阻塞DDL和耗時DDL,在分別開啟和關閉線上分區維護功能的情況下,進行效能對比驗證。

  • 情境一:長事務阻塞DDL

    此情境下對分區表做分區維護DDL操作,由於存在未提交的長事務,從而阻塞DDL操作的進行。被阻塞的DDL操作會進一步阻塞所有新產生的DML操作,導致了資料庫流量跌零。長事務阻塞

    從上圖可以看到,在功能關閉時,當DDL操作發生後,sysbench在該表的流量迅速跌零,資料庫呈現完全停用狀態。使用者只能通過取消DDL操作或者提交所有未提交的長事務後,資料庫才能恢複正常;在功能開啟後,可以看到:

    • 在正常情況下,sysbench的輸送量與線上分區維護功能關閉時完全一致,說明線上分區維護功能的引入並沒有帶來效能方面的損耗;

    • 未提交的長事務並不會阻塞分區維護操作的執行,同時資料庫上的DML流量很穩定,幾乎沒有受到影響。

  • 情境二:耗時DDL

    該情境下,分區維護DDL操作雖然沒有受到其他SQL語句的阻塞,但是在本身執行分區維護DDL操作耗時的情況下,對DML輸送量有影響。耗時DDL

    從上圖可以看到,在功能關閉時,長耗時DDL操作在執行期間導致了DML輸送量的劇烈抖動;在功能開啟後,長耗時DDL操作在執行期間對 DML的輸送量幾乎沒有影響。

查看MDL鎖狀態

線上分區維護功能是通過引入分區層級的MDL鎖,來降低在DML和DDL過程中擷取的鎖粒度,從而增加並發性來實現的。在分區維護過程中,通過performance_schema.metadata_locks表可以查看分區層級的MDL鎖擷取情況。樣本如下:

#在用戶端1上輸出tr表結構
SHOW CREATE TABLE tr\G                                 
*************************** 1. row ***************************    
       Table: tr                                                  
Create Table: CREATE TABLE `tr` (                                  
  `id` int(11) DEFAULT NULL,                                       
  `name` varchar(50) DEFAULT NULL,                                 
  `purchased` date DEFAULT NULL                                    
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 
/*!50100 PARTITION BY RANGE (year(`purchased`))                    
(PARTITION p0 VALUES LESS THAN (1990) ENGINE = InnoDB,             
 PARTITION p1 VALUES LESS THAN (1995) ENGINE = InnoDB,             
 PARTITION p2 VALUES LESS THAN (2000) ENGINE = InnoDB,             
 PARTITION p3 VALUES LESS THAN (2005) ENGINE = InnoDB,            
 PARTITION p4 VALUES LESS THAN (2010) ENGINE = InnoDB,            
 PARTITION p5 VALUES LESS THAN (2015) ENGINE = InnoDB) */         
1 row in set (0.00 sec)

#在用戶端1上開啟事務
BEGIN;                                                 
Query OK, 0 rows affected (0.01 sec)                               
                                                                  
SELECT * FROM tr WHERE purchased >= '2010-01-01';      
+------+----------------+------------+                            
| id   | name           | purchased  |                             
+------+----------------+------------+                             
|    5 | exercise bike  | 2014-05-09 |                         
|    7 | espresso maker | 2011-11-22 |                             
+------+----------------+------------+                             
2 rows in set (0.01 sec)

#在用戶端1上查看MDL鎖的狀態
SELECT * FROM performance_schema.metadata_locks;
+-------------+--------------------+----------------+-------------+-----------------------+---------------------+---------------+-------------+-------------------+-----------------+----------------+
| OBJECT_TYPE | OBJECT_SCHEMA      | OBJECT_NAME    | COLUMN_NAME | OBJECT_INSTANCE_BEGIN | LOCK_TYPE           | LOCK_DURATION | LOCK_STATUS | SOURCE            | OWNER_THREAD_ID | OWNER_EVENT_ID |
+-------------+--------------------+----------------+-------------+-----------------------+---------------------+---------------+-------------+-------------------+-----------------+----------------+
| TABLE       | test               | tr             | NULL        |       140734887898944 | SHARED_READ         | TRANSACTION   | GRANTED     | sql_parse.cc:6759 |              67 |             17 |
| PARTITION   | test               | tr             | p5          |       140734887896704 | SHARED_READ         | TRANSACTION   | GRANTED     | sql_parse.cc:6502 |              67 |             17 |
| TABLE       | performance_schema | metadata_locks | NULL        |       140734879511488 | SHARED_READ         | TRANSACTION   | GRANTED     | sql_parse.cc:6759 |              68 |              4 |
| SCHEMA      | performance_schema | NULL           | NULL        |       140734879511648 | INTENTION_EXCLUSIVE | TRANSACTION   | GRANTED     | dd_schema.cc:108  |              68 |              4 |
+-------------+--------------------+----------------+-------------+-----------------------+---------------------+---------------+-------------+-------------------+-----------------+----------------+
4 rows in set (0.02 sec)

#在用戶端1上可以看到,獲得tr表級的SHARED_READ鎖和剪枝後實際需要訪問p5分區層級的SHARED_READ鎖。接下來,通過用戶端2嘗試將分區p5刪除
ALTER TABLE tr DROP PARTITION p5;

#由於分區p5正在被用戶端1問,所以上述操作會進入等待狀態,通過下述命令可以看到該線程正在等待分區層級的MDL鎖。
SHOW PROCESSLIST;
+----+-----------------+-----------+------+---------+------+-------------------------------------+----------------------------------+
| Id | User            | Host      | db   | Command | Time | State                               | Info                             |
+----+-----------------+-----------+------+---------+------+-------------------------------------+----------------------------------+
|  4 | event_scheduler | localhost | NULL | Daemon  | 1550 | Waiting on empty queue              | NULL                             |
|  8 | root            | localhost | test | Sleep   |  426 |                                     | NULL                             |
|  9 | root            | localhost | NULL | Query   |    0 | starting                            | SHOW PROCESSLIST                 |
| 10 | root            | localhost | test | Query   |   10 | Waiting for partition metadata lock | ALTER TABLE tr DROP PARTITION p5 |
+----+-----------------+-----------+------+---------+------+-------------------------------------+----------------------------------+
4 rows in set (0.00 sec)

#通過用戶端1提交事務後,用戶端2能夠順利完成分區的維護。

查看線上分區維護次數

通過STATUS變數Online_altered_partition參數可以監控進行線上分區維護的次數,樣本如下:

SHOW STATUS LIKE 'Online_altered_partition';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| Online_altered_partition | 2565  |
+--------------------------+-------+
1 row in set (0.00 sec)