PolarDB設計了針對語句的排隊(Statement Queue)機制,將語句進行分桶排隊,盡量把可能具有相同衝突(例如操作相同行)的語句放在一個桶內排隊,減少衝突的開銷。
背景資訊
MySQL的服務層和引擎層在語句並發執行過程中,有很多串列的點容易導致衝突。例如在DML語句中,比較常見的是事務鎖衝突。InnoDB中事務鎖的最細粒度是行級鎖,如果語句針對相同行進行並行作業,會導致比較嚴重的衝突,系統輸送量會隨著並發的增加而遞減。PolarDB提供Statement Queue機制,能夠減少衝突開銷、有效提高資料庫效能。
使用限制
PolarDB叢集版本需為以下版本之一:
PolarDB MySQL版8.0版本且核心小版本需為8.0.1.1.10及以上
PolarDB MySQL版5.7版本且核心小版本需為5.7.1.0.6及以上。
PolarDB MySQL版5.6版本且核心小版本需為20200601及以上。
PolarDB MySQL版5.6版本與PolarDB MySQL版5.7和8.0版本使用了不同的文法實現Statement Queue機制,因此僅PolarDB MySQL版5.7和8.0版本的叢集支援與計劃固化 (Statement Outline)配合使用完成線上修改SQL statement的並發控制。
熱點行效能最佳化總開關開啟後(hotspot參數設定為ON後),將不能使用Statement Queue機制。
效果
在針對單行進行並發UPDATE的情境測試中,相比原生的MySQL,PolarDB有接近4倍的效能提升。
文法
針對PolarDB MySQL版5.6版本,您可以通過以下方式進行hash分桶。
說明POLARDB_STATEMENT_CONCURRENT_QUEUE
文法支援SELECT、UPDATE、INSERT和DELETE等語句。根據int或string值進行hash分桶。
文法:
POLARDB_STATEMENT_CONCURRENT_QUEUE [int | string]
樣本:
insert POLARDB_STATEMENT_CONCURRENT_QUEUE 1 into t values(1, 1, 'xpchild'); update POLARDB_STATEMENT_CONCURRENT_QUEUE 1 t set c=c+1 where id = 1; update POLARDB_STATEMENT_CONCURRENT_QUEUE "xpchild" t set col1 = col1+1 where id =1;
根據WHERE條件中的field值進行hash分桶。
文法:
POLARDB_STATEMENT_CONCURRENT_QUEUE [field]
樣本:
select POLARDB_STATEMENT_CONCURRENT_QUEUE id * from t where 3 = id; update POLARDB_STATEMENT_CONCURRENT_QUEUE id t set c=c+1 where id = 1 and name = 'xpchild';
說明在
POLARDB_STATEMENT_CONCURRENT_QUEUE [field]
文法中,WHERE條件只支援原始欄位(沒有在欄位上使用任何函數、計算等)的二元運算,並且二元運算的右側值必須是數字或者字串。
針對PolarDB MySQL版5.7和8.0,您可以通過以下HINT文法進行hash分桶。
說明ccl_queue_value
文法支援SELECT、UPDATE、INSERT和DELETE等語句。根據int或string值進行hash分桶。
文法:
/*+ CCL_QUEUE_VALUE([INT | STRING)] */
樣本:
update /*+ ccl_queue_value(1) */ t set c=c+1 where id = 1; update /*+ ccl_queue_value('xpchild') */ t set c=c+1 where name = 'xpchild';
根據WHERE條件中的field值進行hash分桶。
文法:
/*+ CCL_QUEUE_FIELD(STRING) */
樣本:
update /*+ ccl_queue_field("id") */ t set c=c+1 where id = 1 and name = 'xpchild';
說明在
/*+ CCL_QUEUE_FIELD(STRING) */
文法中,WHERE條件只支援原始欄位(沒有在欄位上使用任何函數、計算等)的二元運算,並且二元運算的右側值必須是數字或者字串。
變數
PolarDB提供了如下兩個變數來定義語句隊列的桶數量和大小:
變數 | 說明 |
ccl_queue_bucket_count | 表示桶的數量,取值範圍為1~64,預設值為4。 |
ccl_queue_bucket_size | 表示一個桶允許的並發數,取值範圍為1~4096,預設值為64。 |
介面
PolarDB提供以下兩個介面便於您查詢Statement Queue狀態:
dbms_ccl.show_ccl_queue()
查詢當前Statement Queue狀態。
mysql> call dbms_ccl.show_ccl_queue(); +------+-------+-------------------+---------+---------+----------+ | ID | TYPE | CONCURRENCY_COUNT | MATCHED | RUNNING | WAITTING | +------+-------+-------------------+---------+---------+----------+ | 1 | QUEUE | 64 | 1 | 0 | 0 | | 2 | QUEUE | 64 | 40744 | 65 | 6 | | 3 | QUEUE | 64 | 0 | 0 | 0 | | 4 | QUEUE | 64 | 0 | 0 | 0 | +------+-------+-------------------+---------+---------+----------+ 4 rows in set (0.01 sec)
說明對其中的CONCURRENCY_COUNT、MATCHED、RUNNING和WAITTING說明如下:
CONCURRENCY_COUNT:最大並發數。
MATCHED:命中規則的總數。
RUNNING:當前並發的數量。
WAITTING:當前等待的數量。
dbms_ccl.flush_ccl_queue()
清理記憶體中的資料。
mysql> call dbms_ccl.flush_ccl_queue(); Query OK, 0 rows affected (0.00 sec) mysql> call dbms_ccl.show_ccl_queue(); +------+-------+-------------------+---------+---------+----------+ | ID | TYPE | CONCURRENCY_COUNT | MATCHED | RUNNING | WAITTING | +------+-------+-------------------+---------+---------+----------+ | 1 | QUEUE | 64 | 0 | 0 | 0 | | 2 | QUEUE | 64 | 0 | 0 | 0 | | 3 | QUEUE | 64 | 0 | 0 | 0 | | 4 | QUEUE | 64 | 0 | 0 | 0 | +------+-------+-------------------+---------+---------+----------+ 4 rows in set (0.00 sec)
配合Statement Outline線上修改
針對PolarDB MySQL版5.7和8.0版本,Statement Queue還可以配合計劃固化 (Statement Outline)使用實現快速線上修改SQL statement的並發控制,避免介入冗長的應用業務代碼的修改。 下文使用Sysbench的update_non_index為例進行示範。
由於文法不同,PolarDB MySQL版5.6版本不支援與計劃固化 (Statement Outline)配合使用。
測試環境
測試表結構
CREATE TABLE `sbtest1` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `k` int(10) unsigned NOT NULL DEFAULT '0', `c` char(120) NOT NULL DEFAULT '', `pad` char(60) NOT NULL DEFAULT '', PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 MAX_ROWS=1000000;
測試語句
UPDATE sbtest1 SET c='xpchild' WHERE id=0;
測試指令碼
./sysbench --mysql-host= {$ip}\ --mysql-port= {$port}\ --mysql-db=test\ --test=./sysbench/share/sysbench/update_non_index.lua\ --oltp-tables-count=1\ --oltp_table_size=1\ --num-threads=128\ --mysql-user=u0\
測試過程
線上增加Statement Outline。
mysql> CALL DBMS_OUTLN.add_optimizer_outline('test', '', 1, ' /*+ ccl_queue_field("id") */ ', "UPDATE sbtest1 SET c='xpchild' WHERE id=0"); Query OK, 0 rows affected (0.01 sec)
查看Statement Outline。
mysql> call dbms_outln.show_outline(); +------+--------+------------------------------------------------------------------+-----------+-------+------+--------------------------------+------+----------+---------------------------------------------+ | ID | SCHEMA | DIGEST | TYPE | SCOPE | POS | HINT | HIT | OVERFLOW | DIGEST_TEXT | +------+--------+------------------------------------------------------------------+-----------+-------+------+--------------------------------+------+----------+---------------------------------------------+ | 1 | test | 7b945614749e541e0600753367884acff5df7e7ee2f5fb0af5ea58897910f023 | OPTIMIZER | | 1 | /*+ ccl_queue_field("id") */ | 0 | 0 | UPDATE `sbtest1` SET `c` = ? WHERE `id` = ? | +------+--------+------------------------------------------------------------------+-----------+-------+------+--------------------------------+------+----------+---------------------------------------------+ 1 row in set (0.00 sec)
驗證Statement Outline生效。
mysql> explain UPDATE sbtest1 SET c='xpchild' WHERE id=0; +----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ | 1 | UPDATE | sbtest1 | NULL | range | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | Using where | +----+-------------+---------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec) mysql> show warnings; +-------+------+-----------------------------------------------------------------------------------------------------------------------------+ | Level | Code | Message | +-------+------+-----------------------------------------------------------------------------------------------------------------------------+ | Note | 1003 | update /*+ CCL_QUEUE_FIELD('id') */ `test`.`sbtest1` set `test`.`sbtest1`.`c` = 'xpchild' where (`test`.`sbtest1`.`id` = 0) | +-------+------+-----------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec)
查詢Statement Queue狀態。
mysql> call dbms_ccl.show_ccl_queue(); +------+-------+-------------------+---------+---------+----------+ | ID | TYPE | CONCURRENCY_COUNT | MATCHED | RUNNING | WAITTING | +------+-------+-------------------+---------+---------+----------+ | 1 | QUEUE | 64 | 0 | 0 | 0 | | 2 | QUEUE | 64 | 0 | 0 | 0 | | 3 | QUEUE | 64 | 0 | 0 | 0 | | 4 | QUEUE | 64 | 0 | 0 | 0 | +------+-------+-------------------+---------+---------+----------+ 4 rows in set (0.00 sec)
開啟測試。
sysbench --mysql-host= {$ip}\ --mysql-port= {$port}\ --mysql-db=test\ --test=./sysbench/share/sysbench/update_non_index.lua\ --oltp-tables-count=1\ --oltp_table_size=1\ --num-threads=128\ --mysql-user=u0\
驗證測試效果。
mysql> call dbms_ccl.show_ccl_queue(); +------+-------+-------------------+---------+---------+----------+ | ID | TYPE | CONCURRENCY_COUNT | MATCHED | RUNNING | WAITTING | +------+-------+-------------------+---------+---------+----------+ | 1 | QUEUE | 64 | 10996 | 63 | 4 | | 2 | QUEUE | 64 | 0 | 0 | 0 | | 3 | QUEUE | 64 | 0 | 0 | 0 | | 4 | QUEUE | 64 | 0 | 0 | 0 | +------+-------+-------------------+---------+---------+----------+ 4 rows in set (0.03 sec) mysql> call dbms_outln.show_outline(); +------+--------+-----------+-----------+-------+------+--------------------------------+--------+----------+---------------------------------------------+ | ID | SCHEMA | DIGEST | TYPE | SCOPE | POS | HINT | HIT | OVERFLOW | DIGEST_TEXT | +------+--------+-----------+-----------+-------+------+--------------------------------+--------+----------+---------------------------------------------+ | 1 | test | xxxxxxxxx | OPTIMIZER | | 1 | /*+ ccl_queue_field("id") */ | 115795 | 0 | UPDATE `sbtest1` SET `c` = ? WHERE `id` = ? | +------+--------+-----------+-----------+-------+------+--------------------------------+--------+----------+---------------------------------------------+ 1 row in set (0.00 sec)
說明查詢結果顯示Statement Outline命中了115,795次規則,Statement Queue狀態顯示命中了10,996次排隊,當前運行並發63個,排隊等待4個。