9. テストキット Tiny TPC-C

9.1. TPC-Cとは

TPC-C とは、 TPC によって策定されたベンチマーク仕様の一つです。卸売業における注文・支払いなどの業務をモデルにしたトランザクションを実行し、システムの性能を測定します。データベースのER図を以下に示します。

_images/tpc-c.png
  • warehouse : 倉庫を表しています。このテーブルのレコード数がデータベース全体の規模を決めるスケールファクタになっています。
  • district : 配送区域を表しています。倉庫あたり10の配送区域があります。
  • customer : 顧客を表しています。配送区域あたり3,000の顧客がいます。
  • history : 支払い履歴を表しています。初期値として顧客あたり1件の支払い履歴があり、支払いを行うと増加していきます。
  • item : 商品を表しています。このテーブルのレコード数は10万で固定されています。
  • stock : 在庫を表しています。倉庫あたり10万の在庫データを持っています。
  • orders : 注文を表しています。初期値として顧客あたり1つの注文があり、注文を行うと増加していきます。
  • order_line : 注文明細を表しています。注文あたり平均10件の注文明細が作られます。
  • new_orders : 未配送の新規注文を表しています。初期値として30%の顧客が1件ずつ未配送の新規注文を抱えており、注文を行うと増加し、配送が行われると減少します。

TPC-Cでは5種類のトランザクションが定義されています。5種類のトランザクションの実行比率は10:10:1:1:1となっています。

  • New-Order : 注文処理です。
  • Payment : 支払い処理です
  • Order-Status : 注文状況を確認する処理です。
  • Delivery : 配送処理です。
  • Stock-Level : 在庫状況を確認する処理です。

New-Orderトランザクションの内容を擬似コードで表すと、以下のようになります。

SELECT FROM warehouse JOIN customer;
SELECT FROM district FOR UPDATE;
UPDATE district;
INSERT INTO orders;
INSERT INTO new_orders;

LOOP {
  SELECT FROM item;
  SELECT FROM stock FOR UPDATE;
  UPDATE stock;
  INSERT INTO order_line;
}

COMMIT;

同様に、Paymentトランザクションの内容を以下に示します。

SELECT FROM warehouse FOR UPDATE;
UPDATE warehouse;
SELECT FROM district FOR UPDATE;
UPDATE district;
SELECT FROM customer;
SELECT FROM customer FOR UPDATE;
UPDATE customer;
INSERT INTO history;
COMMIT;

Order-Statusトランザクションの内容を以下に示します。

SELECT FROM customer;
SELECT FROM customer;
SELECT FROM orders WHERE id = (SELECT MAX(id) FROM orders);
SELECT FROM order_line;
COMMIT;

Deliveryトランザクションの内容を以下に示します。

LOOP {
  SELECT FROM new_orders WHERE id = (SELECT MIN(id) FROM new_orders) FOR UPDATE;
  DELETE FROM new_orders;
  SELECT FROM orders FOR UPDATE;
  UPDATE orders;
  UPDATE order_line;
  SELECT FROM order_line;
  UPDATE customer;
}

COMMIT;

Stock-Levelトランザクションの内容を以下に示します。

SELECT FROM district JOIN order_line JOIN stock;
COMMIT;

TPC-CのCRUD図を以下に示します。

Transaction warehouse district customer history item stock orders new_orders order_line
New-Order R RU R   R RU C C C
Payment RU RU RU C          
Order-Status     R       R   R
Delivery     U       RU RD RU
Stock-Level   R       R     R

9.2. Tiny TPC-Cとは

Tiny TPC-Cは、TPC-C Standard Specification 5.10.1の仕様を抜粋しJdbcRunnerのスクリプトとして実装したものです。仕様書のうち以下の章節を実装しています。

  • 1 LOGICAL DATABASE DESIGN
  • 2 TRANSACTION and TERMINAL PROFILES
    • 2.4 The New-Order Transaction (2.4.1.1、2.4.3を除く)
    • 2.5 The Payment Transaction (2.5.1.1、2.5.3を除く)
    • 2.6 The Order-Status Transaction (2.6.1.1、2.6.3を除く)
    • 2.7 The Delivery Transaction (2.7.1.1、2.7.2、2.7.3を除く)
    • 2.8 The Stock-Level Transaction (2.8.1、2.8.3を除く)
  • 4 SCALING and DATABASE POPULATION
    • 4.3 Database Population
  • 5 PERFORMANCE METRICS and RESPONSE TIME
    • 5.2 Pacing of Transactions by Emulated Users
      • 5.2.4 Regulation of Transaction Mix

それ以外の章節については実装されていないか、仕様を満たしていません。従ってTiny TPC-Cのテスト結果は正式なTPC-Cのスコアではありません。

Tiny TPC-Cは以下の二つのスクリプトから構成されています。

  • scripts/tpcc_load.js : テストデータ生成用スクリプト
  • scripts/tpcc.js : テスト用スクリプト

9.3. 対応RDBMS

Tiny TPC-Cは以下のRDBMSに対応しています。

  • Oracle Database 11g Release 2
  • MySQL 5.1
  • PostgreSQL 8.4

RDBMSのバージョンは実際に動作確認を行ったバージョンを示しており、これ以外のバージョンでも動作する可能性はあります。

9.4. テストの準備

MySQLにおけるテストの準備手順を以下に示します。Oracle、PostgreSQLについてはscripts/tpcc_load.jsのコメントをご参照ください。

9.4.1. ユーザの作成

MySQLにrootユーザで接続し、tpccユーザを作成します。

> mysql -u root
mysql> GRANT ALL PRIVILEGES ON tpcc.* TO tpcc@'%' IDENTIFIED BY 'tpcc';
Query OK, 0 rows affected (0.00 sec)

ネットワーク環境によっては、接続元ホストを制限したりtpccをより安全なパスワードに変更することをおすすめします。

9.4.2. データベースの作成

tpccデータベースを作成します。

mysql> CREATE DATABASE tpcc;
Query OK, 1 row affected (0.00 sec)

9.4.3. テストデータの生成

scripts/tpcc_load.jsを用いてテストデータの生成を行います。このスクリプトは以下の処理を行っています。

  • テーブルの削除
  • テーブルの作成
  • データロード
  • インデックスの作成 (MySQLのみデータロード前に作成)
  • 統計情報の更新 (Oracle、PostgreSQLのみ実施)
> java JR scripts\tpcc_load.js

17:22:38 [INFO ] > JdbcRunner 1.1
17:22:38 [INFO ] [Config]
Program start time   : 20100430-172237
Script filename      : scripts\tpcc_load.js
JDBC driver          : -
JDBC URL             : jdbc:mysql://localhost:3306/tpcc?rewriteBatchedStatements=true
JDBC user            : tpcc
Load mode            : true
Number of agents     : 4
Auto commit          : false
Debug mode           : false
Trace mode           : false
Log directory        : logs
Parameter 0          : 0
Parameter 1          : 0
Parameter 2          : 0
Parameter 3          : 0
Parameter 4          : 0
Parameter 5          : 0
Parameter 6          : 0
Parameter 7          : 0
Parameter 8          : 0
Parameter 9          : 0
17:22:40 [INFO ] Tiny TPC-C 1.0 - data loader
17:22:40 [INFO ] -param0  : Scale factor (default : 16)
17:22:40 [INFO ] -nAgents : Parallel loading degree (default : 4)
17:22:40 [INFO ] Scale factor            : 16
17:22:40 [INFO ] Parallel loading degree : 4
17:22:40 [INFO ] Dropping tables ...
17:22:40 [WARN ] JavaException: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table 'order_line'
17:22:40 [WARN ] JavaException: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table 'new_orders'
17:22:40 [WARN ] JavaException: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table 'orders'
17:22:40 [WARN ] JavaException: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table 'stock'
17:22:40 [WARN ] JavaException: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table 'item'
17:22:40 [WARN ] JavaException: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table 'history'
17:22:40 [WARN ] JavaException: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table 'customer'
17:22:40 [WARN ] JavaException: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table 'district'
17:22:40 [WARN ] JavaException: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown table 'warehouse'
17:22:40 [INFO ] Creating tables ...
17:22:41 [INFO ] Loading item ...
17:22:44 [INFO ] item : 10000 / 100000
17:22:45 [INFO ] item : 20000 / 100000
17:22:46 [INFO ] item : 30000 / 100000
17:22:47 [INFO ] item : 40000 / 100000
17:22:48 [INFO ] item : 50000 / 100000
17:22:49 [INFO ] item : 60000 / 100000
17:22:50 [INFO ] item : 70000 / 100000
17:22:51 [INFO ] item : 80000 / 100000
17:22:52 [INFO ] item : 90000 / 100000
17:22:53 [INFO ] item : 100000 / 100000
17:22:53 [INFO ] Loading warehouse id 2 by agent 1 ...
17:22:53 [INFO ] [Agent 1] Loading warehouse ...
17:22:53 [INFO ] Loading warehouse id 3 by agent 3 ...
17:22:53 [INFO ] [Agent 3] Loading warehouse ...
17:22:53 [INFO ] Loading warehouse id 1 by agent 0 ...
17:22:53 [INFO ] Loading warehouse id 4 by agent 2 ...
17:22:53 [INFO ] [Agent 0] Loading warehouse ...
17:22:53 [INFO ] [Agent 2] Loading warehouse ...
17:22:53 [INFO ] [Agent 0] Loading district ...
17:22:53 [INFO ] [Agent 3] Loading district ...
17:22:53 [INFO ] [Agent 1] Loading district ...
17:22:53 [INFO ] [Agent 2] Loading district ...
17:22:53 [INFO ] [Agent 0] Loading customer and history ...
17:22:53 [INFO ] [Agent 2] Loading customer and history ...
17:22:53 [INFO ] [Agent 1] Loading customer and history ...
17:22:53 [INFO ] [Agent 3] Loading customer and history ...
17:23:27 [INFO ] [Agent 3] customer : 10000 / 30000
17:23:27 [INFO ] [Agent 0] customer : 10000 / 30000
17:23:27 [INFO ] [Agent 1] customer : 10000 / 30000
17:23:28 [INFO ] [Agent 2] customer : 10000 / 30000
...
17:56:33 [INFO ] [Agent 2] orders : 30000 / 30000
17:56:37 [INFO ] [Agent 3] orders : 30000 / 30000
17:56:47 [INFO ] [Agent 0] orders : 30000 / 30000
17:56:47 [INFO ] Completed.
17:56:47 [INFO ] < JdbcRunner SUCCESS

「Unknown table ‘order_line’」などの警告は、存在しないテーブルを削除しようとして出力されるものです。無視して構いません。

-param0を指定することによって、スケールファクタを変更することが可能です。スケールファクタ1あたりwarehouseテーブルが1レコード増加し、その他のテーブルもレコード数が以下のように増加します。デフォルトのスケールファクタは16です。

Table Records
warehouse sf x 1
district sf x 10
customer sf x 30,000
history sf x 30,000
item 100,000
stock sf x 100,000
orders sf x 30,000
new_orders sf x 9,000
order_line sf x 300,000 (approx.)

-nAgentsを指定することによって、ロードの並列度を変更することが可能です。RDBMSがCPUスケーラビリティに優れておりクアッドコアなどCPUコア数の多い環境では、並列度を上げることでロード時間を短縮することができます。デフォルトの並列度は4です。

$ java JR scripts/tpcc_load.js -nAgents 8 -param0 100

9.5. テストの実行

scripts/tpcc.jsを用いてテストを実行します。JdbcRunnerを動作させるマシンは、テスト対象のマシンとは別に用意することを強くおすすめします。

Oracle Sun JDK/JREを利用する際は、Java HotSpot Server VMを用いることをおすすめします。詳細は JDK 6 仮想マシン (VM) 関連 API & 開発者ガイド をご参照ください。

> java -server JR scripts\tpcc.js -jdbcUrl jdbc:mysql://server/tpcc

12:05:49 [INFO ] > JdbcRunner 1.1
12:05:49 [INFO ] [Config]
Program start time   : 20100501-120548
Script filename      : scripts\tpcc.js
JDBC driver          : -
JDBC URL             : jdbc:mysql://server/tpcc
JDBC user            : tpcc
Warmup time          : 300 sec
Measurement time     : 900 sec
Number of tx types   : 5
Number of agents     : 16
Connection pool size : 16
Statement cache size : 40
Auto commit          : false
Sleep time           : 0,0,0,0,0 msec
Throttle             : - tps (total)
Debug mode           : false
Trace mode           : false
Log directory        : logs
Parameter 0          : 0
Parameter 1          : 0
Parameter 2          : 0
Parameter 3          : 0
Parameter 4          : 0
Parameter 5          : 0
Parameter 6          : 0
Parameter 7          : 0
Parameter 8          : 0
Parameter 9          : 0
12:05:53 [INFO ] Tiny TPC-C 1.0
12:05:53 [INFO ] Scale factor : 16
12:05:53 [INFO ] tx0 : New-Order transaction
12:05:53 [INFO ] tx1 : Payment transaction
12:05:53 [INFO ] tx2 : Order-Status transaction
12:05:53 [INFO ] tx3 : Delivery transaction
12:05:53 [INFO ] tx4 : Stock-Level transaction
12:05:55 [INFO ] [Warmup] -299 sec, 0,0,0,0,0 tps, (0,0,0,0,0 tx)
12:05:56 [INFO ] [Warmup] -298 sec, 0,0,0,0,0 tps, (0,0,0,0,0 tx)
12:05:57 [INFO ] [Warmup] -297 sec, 0,5,0,0,0 tps, (0,5,0,0,0 tx)
12:05:58 [INFO ] [Warmup] -296 sec, 0,0,1,0,0 tps, (0,5,1,0,0 tx)
12:05:59 [INFO ] [Warmup] -295 sec, 3,0,0,0,0 tps, (3,5,1,0,0 tx)
...
12:25:49 [INFO ] [Progress] 896 sec, 1,6,0,3,1 tps, 4569,4789,463,463,430 tx
12:25:51 [INFO ] [Progress] 897 sec, 5,0,2,0,0 tps, 4574,4789,465,463,430 tx
12:25:51 [INFO ] [Progress] 898 sec, 7,9,1,2,0 tps, 4581,4798,466,465,430 tx
12:25:53 [INFO ] [Progress] 899 sec, 2,10,1,0,1 tps, 4583,4808,467,465,431 tx
12:25:54 [INFO ] [Progress] 900 sec, 4,7,0,0,0 tps, 4587,4815,467,465,431 tx
12:25:55 [INFO ] [Total tx count] 4587,4815,467,465,431 tx
12:25:55 [INFO ] [Throughput] 5,5,0,0,0 tps
12:25:55 [INFO ] [Response time (minimum)] 52,5,4,807,5 msec
12:25:55 [INFO ] [Response time (50%tile)] 1640,552,687,3060,1675 msec
12:25:55 [INFO ] [Response time (90%tile)] 3034,1295,1310,4779,6567 msec
12:25:55 [INFO ] [Response time (95%tile)] 3487,1666,1703,5170,8177 msec
12:25:55 [INFO ] [Response time (99%tile)] 4512,2713,2280,7083,11304 msec
12:25:55 [INFO ] [Response time (maximum)] 8763,6383,3301,7900,12974 msec
12:25:55 [INFO ] < JdbcRunner SUCCESS

TPC-Cには5種類のトランザクションが定義されていることから、Tiny TPC-Cではそれぞれを別のトランザクションとして集計しています。スループット、レスポンスタイムの出力はそれぞれ左からNew-Order、Payment、Order-Status、Delivery、Stock-Levelトランザクションのものを表しています。

TPC-CのスコアにはNew-Orderトランザクションの1分あたりの実行回数を用います。上記の例では15分間で4,587txですから、スコアは305.8tpmとなります。