全部產品
Search
文件中心

PolarDB:Statement Queue

更新時間:Jul 06, 2024

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_COUNTMATCHEDRUNNINGWAITTING說明如下:

    • 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\
  • 測試過程

    1. 線上增加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)
    2. 查看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)
    3. 驗證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)
    4. 查詢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)
    5. 開啟測試。

      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\
    6. 驗證測試效果。

      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個。