同時ステートメントの実行中、MySQLサーバーとエンジンは互いに競合する可能性があります。 この問題を解決するために、AliSQLは、同じリソースを必要とするステートメントが同じバケットにキューできるようにするステートメントキュー機能を提供します。 たとえば、同じバケット内のテーブルキューの同じ行を必要とするステートメントです。 この機能は、潜在的な競合によって引き起こされるオーバーヘッドを削減し、ApsaraDB RDS for MySQLインスタンスのパフォーマンスを向上させるのに役立ちます。
背景情報
同時ステートメントの実行中に、MySQLサーバーとエンジンは、いくつかのシリアル操作で互いに競合する可能性があります。 たとえば、トランザクションロックの競合は、DMLステートメントの実行中に一般的です。 InnoDBストレージエンジンは、行への正確なリソースロックをサポートします。 複数のDMLステートメントが行内で同時に実行されると、深刻な競合が発生する可能性があります。 データベースシステムの全体的なスループットは、同時DMLステートメントの数に比例して低下します。 AliSQLは、競合オーバーヘッドを削減し、インスタンスのパフォーマンスを向上させるステートメントキュー機能を提供します。
前提条件
RDSインスタンスは、次のMySQLバージョンとRDSエディションのいずれかを実行します。
RDS Basic EditionまたはRDS High-availability Editionで20191115以降のマイナーエンジンバージョンを使用したMySQL 8.0
RDS Basic EditionまたはRDS High-availability Editionで20200630以降のマイナーエンジンバージョンを使用したMySQL 5.7
変数
AliSQLは、ステートメントキューのバケット数とサイズを定義するために使用される2つの変数を提供します。
ccl_queue_bucket_count: ステートメントキューで許可されているバケットの数。
有効な値: 1 ~ 64。
デフォルト値: 4。
ccl_queue_bucket_size: バケットごとに許可される同時ステートメントの数。
有効な値: 1 ~ 4096
デフォルト値: 64。
ApsaraDB RDSコンソールで変数を変更できます。 詳細は、「インスタンスパラメーターの変更」をご参照ください。
構文
AliSQLは2つのヒントをサポートします。
ccl_queue_value
AliSQLは、ハッシュアルゴリズムを使用して、指定されたフィールドの値に基づいて各ステートメントが配置されるバケットを決定します。
構文:
/* + ccl_queue_value([int | string]) */
例:
update /* + ccl_queue_value(1) */ t set c=c + 1 (id = 1); update /* + ccl_queue_value('xyz') */ t set c=c + 1ここでname = 'xyz';
ccl_queue_field
AliSQLは、ハッシュアルゴリズムを使用して、WHERE句で指定されたフィールドの値に基づいて、各ステートメントが配置されるバケットを決定します。
構文:
/* + ccl_queue_field (文字列) */
例:
update /* + ccl_queue_field(id) */ t set c=c + 1ここで、id = 1およびname = 'xyz';
説明上記のヒントは更新後に配置する必要があります。
ccl_queue_fieldヒントは、一度に1つのフィールドのみを指定します。
/* + ccl_queue_field(id name) */
ヒントに構文エラーが含まれている場合、同時実行制御 (CCL) キューは有効になりません。/* + ccl_queue_field(id) ccl_queue_field(name) */
ヒントが重複している場合、最初のヒントで指定されたフィールドが優先されます。ccl_queue_fieldヒントで指定されたフィールドは、WHERE句で使用する必要があります。
ccl_queue_fieldヒントでは、WHERE句はrawフィールドでのみバイナリ演算子をサポートします。 これらの生フィールドは、関数または計算操作を使用して変更されていません。 さらに、このようなバイナリ演算子の右オペランドは、数値または文字列でなければなりません。
関数
AliSQLには、ステートメントキューのステータスを照会するために使用される2つの関数があります。
dbms_ccl.show_ccl_queue()
この関数は、現在のステートメントキューのステータスを照会するために使用されます。
mysql> dbms_ccl.show_ccl_queue() を呼び出します。------ ------- ------------------- ----------------------------------------- | ID | TYPE | CONCURRENCY_COUNT | 一致 | 実行中 | 待機中 | ------ ------- ------------------- ----------------------------------------- | 1 | キュー | 64 | 1 | 0 | 0 | | 2 | キュー | 64 | 40744 | 65 | 6 | | 3 | キュー | 64 | 0 | 0 | 0 | | 4 | キュー | 64 | 0 | 0 | 0 | ------ ------- ------------------- ----------------------------------------- セットの4列 (0.01秒)
下表に、各パラメーターを説明します。
パラメーター
説明
CONCURRENCY_カウント
許可される同時ステートメントの最大数。
マッチした
指定されたルールにヒットしたステートメントの総数。
ランニング
同時に実行されているステートメントの数。
待っている
キューで待機しているステートメントの数。
dbms_ccl.flush_ccl_queue()
この関数は、ステートメントキューに関するデータをメモリから削除するために使用されます。
mysql> call dbms_ccl.flush_ccl_queue(); クエリOK、影響を受ける0行 (0.00秒) mysql> dbms_ccl.show_ccl_queue() を呼び出します。------ ------- ------------------- ----------------------------------------- | ID | TYPE | CONCURRENCY_COUNT | 一致 | 実行中 | 待機中 | ------ ------- ------------------- ----------------------------------------- | 1 | キュー | 64 | 0 | 0 | 0 | | 2 | キュー | 64 | 0 | 0 | 0 | | 3 | キュー | 64 | 0 | 0 | 0 | | 4 | キュー | 64 | 0 | 0 | 0 | ------ ------- ------------------- ----------------------------------------- セットの4列 (0.00秒)
実践
機能テスト
ステートメントキューは、ステートメントアウトライン機能と連携して、アプリケーションコードのオンライン更新をサポートできます。 詳細については、「ステートメントアウトライン」をご参照ください。 次の例では、Sysbenchを使用してupdate_non_indexスクリプトを実行します。
テスト環境
テーブルのスキーマ
テーブル 'sbtest1' の作成 ( 'id' int(10) 符号なしNOT NULL AUTO_INCREMENT、 'k' int (10) unsigned NOT NULL DEFAULT '0', 'c' char(120) NOT NULL DEFAULT ''、 'pad'char (60) NOT NULL DEFAULT ''、 主要なキー ('id') 、 キー 'k_1 ' ('k') エンジン=InnoDB AUTO_INCREMENT=2デフォルト料金=utf8 MAX_ROWS=1000000;
ステートメント
更新sbtest1 SET c='xyz' WHERE id=0;
Script
. /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_OUTNN.add_optimizer_outline ('test', '', 1, ' /* + ccl_queue_field(id) */ ' 、 "UPDATE sbtest1 SET c='xyz' WHERE id=0"); クエリOK、影響を受ける0行 (0.01秒)
作成したステートメントアウトラインを表示します。
mysql> dbms_outln.show_outline() を呼び出します。------ -------- ------------------------------------------------------------------ ---------------------------------- -------------------------------- ------------------ --------------------------------------------- + | ID | スキーマ | DIGEST | タイプ | スコープ | POS | ヒント | ヒット | オーバーフロー | DIGEST_TEXT | ------ -------- ------------------------------------------------------------------ ---------------------------------- -------------------------------- ------------------ --------------------------------------------- + | 1 | test | 7b945614749e541e0600753367884acff5df7e7ee2f5fb0af5ea58897910f023 | OPTIMIZER | | 1 | /* + ccl_queue_field(id) */ | 0 | 0 | UPDATE 'sbtest1' SET 'c' = ? どこ 'id' = ? | ------ -------- ------------------------------------------------------------------ ---------------------------------- -------------------------------- ------------------ --------------------------------------------- + 1行セット (0.00秒)
ステートメントのアウトラインが有効になっていることを確認します。
mysql> UPDATE sbtest1 SET c='xyz' 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列、1警告 (0.00秒) mysql> 警告を表示します。+ ------ ------ + ----------------------------------------------------------------------------------------------------------------------------- + | レベル | コード | メッセージ | + ------ ------ + ----------------------------------------------------------------------------------------------------------------------------- + | 注 | 1003 | update /* + ccl_queue_field(id) */ 'test'.'sbtest1' set 'test'.'sbtest1'.'c' = 'xyz' ここで ('test'.'sbtest1'.'id' = 0) | + ------ ------ + ----------------------------------------------------------------------------------------------------------------------------- + 1行セット (0.00秒)
使用されているステートメントキューのステータスを照会します。
mysql> dbms_ccl.show_ccl_queue() を呼び出します。------ ------- ------------------- ----------------------------------------- | ID | TYPE | CONCURRENCY_COUNT | 一致 | 実行中 | 待機中 | ------ ------- ------------------- ----------------------------------------- | 1 | キュー | 64 | 0 | 0 | 0 | | 2 | キュー | 64 | 0 | 0 | 0 | | 3 | キュー | 64 | 0 | 0 | 0 | | 4 | キュー | 64 | 0 | 0 | 0 | ------ ------- ------------------- ----------------------------------------- セットの4列 (0.00秒)
テストを開始します。
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> dbms_ccl.show_ccl_queue() を呼び出します。------ ------- ------------------- ----------------------------------------- | ID | TYPE | CONCURRENCY_COUNT | 一致 | 実行中 | 待機中 | ------ ------- ------------------- ----------------------------------------- | 1 | キュー | 64 | 10996 | 63 | 4 | | 2 | キュー | 64 | 0 | 0 | 0 | | 3 | キュー | 64 | 0 | 0 | 0 | | 4 | キュー | 64 | 0 | 0 | 0 | ------ ------- ------------------- ----------------------------------------- セットの4列 (0.03秒) mysql> dbms_outln.show_outline() を呼び出します。------ --------- ---------- ---------------------------------------------------------------- --------------------------------------------- + | ID | スキーマ | DIGEST | タイプ | スコープ | POS | ヒント | ヒット | オーバーフロー | DIGEST_TEXT | ------ --------- ---------- ---------------------------------------------------------------- --------------------------------------------- + | 1 | test | xxxxxxxxx | OPTIMIZER | | 1 | /* + ccl_queue_field(id) */ | 115795 | 0 | UPDATE 'sbtest1' SET 'c' = ? どこ 'id' = ? | ------ --------- ---------- ---------------------------------------------------------------- --------------------------------------------- + 1行セット (0.00秒)
説明クエリ結果に基づいて、合計115,795のステートメントがステートメントアウトラインのルールにヒットし、合計10,996のステートメントがステートメントキューのルールにヒットし、合計63のステートメントが同時に実行され、4つのステートメントがキューで待機しています。
パフォーマンステスト
テスト環境
アプリケーションは、Alibaba Cloud ECS (Elastic Compute Service) インスタンスにデプロイされています。
RDSインスタンスは、8 CPUコアと16 GBのメモリを提供し、拡張SSD (ESSD) を使用します。
RDSインスタンスはRDS High-availability Editionを実行し、非同期データレプリケーションを使用します。
テスト ケース
次のテストケースは、IDが1に設定されているレコードに対して同時更新を実行するために使用されます。
pathtest = string.match(test, "(.*/)") pathtestの場合 dofile(pathtest .. "oltp_common.lua") else require("oltp_common") 終了 関数thread_init() drv = sysbench.sql.driver() con = drv:connect() 終了 関数event() ローカルval_name val_name = "'sdnjkmoklvnseajinvijsfdnvkjsnfjvn" .. sb_rand_uniform(1、4096) .. "'" query = "UPDATE sbtest1 SET c=" .. val_name .. "WHERE id=1" rs = db_query (クエリ) 終了
テスト結果
ステートメントキュー機能を有効にすると、1秒あたりのクエリ数 (QPS) が大幅に増加し、同時クエリの数が多い場合はその増加が顕著になります。
説明ステートメントキュー機能が無効になっている場合、ストレステストのスレッド数が4,096すると、プライマリ /セカンダリの切り替えが発生します。 その結果、QPSは0となる。