今度はブログ系のテーブル構成になっています。
サーバ環境
HP DL350
Linux version 2.6.9-5.ELsmp (bhcompile@decompose.build.redhat.com) (gcc version 3.4.3 20041212 (Red Hat 3.4.3-9.EL4)) #1 SMP Wed Jan 5 19:30:39 EST 2005Intel(R) Pentium(R) III CPU family×2
cpu MHz : 1396.686
cache size : 512 KB3GB of RAM
OSもMySQLも32bit。
MySQLは5.0.37。
要するに同じ構造でInnoDB(テーブル名:entry,entry_comment)、MyISAM(テーブル名:entry2,entry_comment2)用のテーブルを作成しました。
entryとentry2は記事を格納するテーブルで100万件登録されています。
entry_commentとentry_comment2はコメントを格納するテーブルで、こちらも100万件登録されています。
PRIMARY KEYであるidには1~1000000の値がセットされています。
1記事に対して、1コメントが存在しています。
[mysqld]
port = 3306socket = /tmp/mysql.sock
skip-lockingsort_buffer_size = 1M
read_buffer_size = 1M
read_rnd_buffer_size = 4M
myisam_sort_buffer_size = 64M
thread_cache_size = 1024
max_allowed_packet = 16M
key_buffer_size=1250Minnodb_buffer_pool_size=1250M
innodb_log_file_size=10M
innodb_thread_concurrency=8
max_connections=1500
table_cache=1024
net_read_timeout=30
net_write_timeout=30
back_log=128
※クエリーキャッシュを利用すると計測の意味が無くなってしまうので使用していません。
上記の内容で計測したのは
InnoDB vs MyISAM パフォーマンス比較 Left Join
InnoDB vs MyISAM パフォーマンス比較 Inner Join
InnoDB vs MyISAM パフォーマンス比較 副問い合わせ
です。
6月 05
InnoDB vs MyISAMシリーズはまだまだ続きます。
前回はこちら。
今回はLimitの件数の指定でどう変化するかと試してみます。
測定環境についてはこちらを参照して下さい。
・データ件数は100万件
・こちらの構造のテーブルをInnoDBとMyISAMで作成して処理速度を比較
以下SQL中の「テーブル名 normal」にはMyISAMなら normal2 がセットされます。
SELECT name FROM normal WHERE country_id = %d LIMIT 50
※%dは1~200でランダムに変化
※country_idは1~200のランダム値で全体が100万件なので、非一意INDEXで5000件のうち先頭50件を取得します
※取得カラムはINDEX以外
| スレッド数 | MyISAM | InnoDB |
| 1 | 1,210.67 | 1,352.00 |
| 2 | 1,994.00 | 1,975.33 |
| 4 | 1,991.00 | 1,962.00 |
| 8 | 2,000.00 | 1,855.00 |
| 16 | 1,972.67 | 1,681.00 |
| 32 | 1,851.33 | 1,585.33 |
| 64 | 1,735.33 | 1,494.00 |
MyISAM 最高性能:最低性能= 1 : 0.87
InnoDB 最高性能:最低性能= 1 : 0.76
次に行きましょう。
SELECT name FROM normal WHERE country_id = %d LIMIT 5
※前述のLIMIT 50をLIMIT 5に変更しただけです。
| スレッド数 | MyISAM | InnoDB |
| 1 | 2,873.33 | 3,582.67 |
| 2 | 4,652.33 | 5,115.67 |
| 4 | 4,650.33 | 5,112.33 |
| 8 | 4,657.00 | 4,941.00 |
| 16 | 4,436.00 | 4,311.67 |
| 32 | 3,887.33 | 3,722.67 |
| 64 | 3,577.33 | 3,447.00 |
MyISAM 最高性能:最低性能= 1 : 0.77
InnoDB 最高性能:最低性能= 1 : 0.67
なるほど・・・・。
SELECT name FROM normal WHERE country_id = %d LIMIT 1
※前述のLIMIT 5をLIMIT 1に変更しただけです。
| スレッド数 | MyISAM | InnoDB |
| 1 | 3,297.00 | 3,787.00 |
| 2 | 5,117.00 | 5,409.67 |
| 4 | 5,290.33 | 5,379.33 |
| 8 | 5,396.33 | 5,185.67 |
| 16 | 5,066.33 | 4,551.33 |
| 32 | 4,378.00 | 3,909.00 |
| 64 | 3,989.33 | 3,313.67 |
MyISAM 最高性能:最低性能= 1 : 0.74
InnoDB 最高性能:最低性能= 1 : 0.61
ここまで見てくるとハッキリしたと思います。
とりあえずの結論です。
6月 04
なんかしつこいですがInnoDB vs MyISAMシリーズが続いています。
前回までではPrimaryKey,UniqueIndex、非UniqueIndexで1~数件を取得する
パターンが主ですが今回はそれなりの件数を取得するパターンを試してみます。
測定環境についてはこちらを参照して下さい。
・データ件数は100万件
・こちらの構造のテーブルをInnoDBとMyISAMで作成して処理速度を比較
以下SQL中の「テーブル名 normal」にはMyISAMなら normal2 がセットされます。
SELECT name FROM normal WHERE country_id = %d
※%dは1~200でランダムに変化
※country_idは1~200のランダム値で全体が100万件なので、非一意INDEXで5000件のデータを取得します
※取得カラムはINDEX以外
| スレッド数 | MyISAM | InnoDB |
| 1 | 20.00 | 23.00 |
| 2 | 32.00 | 33.00 |
| 4 | 32.00 | 31.67 |
| 8 | 32.67 | 30.33 |
| 16 | 32.00 | 30.00 |
| 32 | 32.00 | 28.67 |
| 64 | 31.33 | 27.00 |
ますます同時スレッド数による性能劣化が緩やかになります。
MyISAMは同時スレッド数を上げても、性能がほとんど変化しません。。
スレッド数2~4くらいはほとんど互角です。
SELECT min(dob) FROM normal
※MINなのでFullScanの発生は確実
| スレッド数 | MyISAM | InnoDB |
| 1 | 0.45 | 0.59 |
| 2 | 0.79 | 1.07 |
| 4 | 0.79 | 1.09/td> |
| 8 | 0.82 | 1.14 |
| 16 | 0.84 | 1.18 |
| 32 | 0.84 | 1.20 |
| 64 | 0.93 | 1.20 |
30~40%くらいInnoDBの方が高速です。
同時スレッド数上げても性能劣化が見られません。
というかかえってスループットが若干ですが向上します。
InnoDBとMyISAMの同時スレッドに対するスケーラビリィティの特性が関係が見えてきたような気がします。
次回、もう少し深追いして確認してみたいと思います。
6月 03
InnoDB vs MyISAMシリーズがまだ続いています。
前回までで環境や初期化パラメータの設定が落ち着いたので
本格的にInnoDBとMyISAMのパフォーマンスを比較してみます。
測定環境についてはこちらを参照して下さい。
・データ件数は100万件
・こちらの構造のテーブルをInnoDBとMyISAMで作成して処理速度を比較
以下SQL中の「テーブル名 normal」にはMyISAMなら normal2 がセットされます。
SELECT name FROM normal WHERE id = %d
※%dは1~100万でランダムに変化
※取得カラムはPK以外
| スレッド数 | MyISAM | InnoDB |
| 1 | 6,674.33 | 6,948.33 |
| 2 | 11,003.33 | 11,520.00 |
| 4 | 11,432.00 | 12,012.00 |
| 8 | 11,219.33 | 11,205.00 |
| 16 | 9,774.67 | 9,292.00 |
| 32 | 8,638.67 | 7,497.00 |
| 64 | 6,618.00 | 5,965.33 |
前回も書いた通りほぼ「同点」です。
それにしても同時スレッドを上げるときれいに性能が落ちていきます。
SELECT name FROM normal WHERE email = %s
※%sはランダムに変化
※取得カラムはINDEX以外
| スレッド数 | MyISAM | InnoDB |
| 1 | 3,906.00 | 4,010.33 |
| 2 | 6,634.33 | 6,702.67 |
| 4 | 6,602.67 | 6,677.33 |
| 8 | 6,229.00 | 6,270.00 |
| 16 | 5,979.33 | 5,793.67 |
| 32 | 5,161.67 | 5,034.33 |
| 64 | 4,929.33 | 4,534.33 |
これもほぼ「同点」と言ってよいと思います。
しかしPrimaryKeyに比べると55%程度の処理しか出来ません。
InnoDBの場合は、PrimaryKeyがクラスターインデックスなので理解できます。
クラスターインデックスであるPrimaryKeyの場合は、PrimaryKeyを取得すると同時にデータページも読み込まれるのですが、通常のINDEXの場合は
1)INDEXを取得
2)INDEXとセットで格納されているPrimaryKeyによってデータを取得
の経路になるため、その分がオーバヘッドになっているはずです。
でもMyISAMの場合は、PrimaryKeyでもINDEXでもOSのIOによってデータページを読み込むはずなのですから、あまり差がないはずなのですが。
別の機会に調べたいと思います。
SELECT name FROM normal WHERE id between %d1 and %d2
※(%d1は1~100万でランダムに変化 %d2は%d1+20)
※常に20件取得される
※取得カラムはINDEX以外
| スレッド数 | MyISAM | InnoDB |
| 1 | 1,008.00 | 1,792.67 |
| 2 | 1,627.00 | 2,812.67 |
| 4 | 1,632.67 | 2,825.00 |
| 8 | 1,652.00 | 2,760.67 |
| 16 | 1,640.67 | 2,536.33 |
| 32 | 1,627.33 | 2,299.33 |
| 64 | 1,528.67 | 2,097.33 |
70~80%ほどInnoDBが高速になっています。
これもInnoDBのPrimaryKeyがクラスターインデックスであるためでしょうか。
つまり、PrimaryKeyを読み込む際に、キーの値が近いものが隣接しているので、同時にデータページに読み込む確率が高いため。
なんか都合の良い解釈でしょうか?
SELECT name FROM $tableName WHERE country_id = %d and state_id between %d1 and %d2
※%dは1~200,%d1は1~50,%d2は%d1に1を足したもの
※取得カラムはINDEX以外
※country_idは1~200、state_idは1~50の範囲なので、country_id+state_idで同じ値は100件づつ存在する。%d2は%d1に1を足したものなので200件づつ取得する。
| スレッド数 | MyISAM | InnoDB |
| 1 | 373.67 | 424.00 |
| 2 | 614.00 | 645.33 |
| 4 | 616.67 | 637.00 |
| 8 | 630.00 | 603.33 |
| 16 | 605.00 | 580.67 |
| 32 | 622.33 | 565.33 |
| 64 | 579.00 | 533.33 |
これはほぼ同点です。
ただPrimaryKeyで1件取得する場合に比べて、スレッド数を上げたときの性能低下の度合いが緩やかです。
特にMyISAMはあまり性能劣化しません。
今後、考えたいと思います。
SELECT name FROM normal WHERE country_id = %d LIMIT 5
※%dは1~200でランダム
※取得カラムはINDEX以外
※country_idは1~200の範囲なので、country_idで同じ値は5000件づつ存在する。その先頭5件を取得する。ただし取得時のソートなし。
| スレッド数 | MyISAM | InnoDB |
| 1 | 3,084.33 | 3,671.33 |
| 2 | 4,913.67 | 5,191.67 |
| 4 | 4,897.33 | 5,258.00 |
| 8 | 4,844.67 | 4,946.00 |
| 16 | 4,577.67 | 4,348.33 |
| 32 | 4,072.00 | 3,757.67 |
| 64 | 3,850.67 | 3,404.67 |
これもほぼ同点です。
ただ性能劣化の度合いが、「PrimaryKeyで1件取得」と「非UniqueIndexで範囲検索」の中間くらいですね。
まだまだ続きます。
6月 02
innodb_thread_concurrencyとかでこんなことを書きました。
・innodb_thread_concurrency InnoDB の処理を同時に実行できるスレッド数の上限値
・MySQL 5.0.8 以降にデフォルト値が 8 から 20 に変更され、無制限を意味する値が 500 から 20 に変更されている
(つまり、デフォルトは制限なし)。
・最大スレッド数を無制限にすることで 10% 程度性能を上げることができた。
※自分で調べたのではなく、OSDL DBT-1 (ODBC版) による MySQL 5.0 性能測定 CPU 構成の差異による特性の分析と考察 Intel Xeon デュアルコア編 からの引用でした。
気になったので自分で計測してみました。
測定環境についてはこちらを参照して下さい。
・データ件数は100万件
・こちらの構造のテーブルをInnoDBとMyISAMで作成して処理速度を比較
で、innodb_thread_concurrency を2,4,8,20(無制限を意味する)と変えながら計測してみました。
| スレッド数 | 2 | 4 | 8 | 20 |
| 1 | 7,019.00 | 6,970.00 | 6,948.33 | 6,952.67 |
| 2 | 11,898.67 | 11,883.33 | 11,520.00 | 11,520.67 |
| 4 | 11,850.00 | 11,854.33 | 12,012.00 | 11,672.00 |
| 8 | 10,455.33 | 11,027.67 | 11,205.00 | 11,016.33 |
| 16 | 9,087.00 | 9,129.00 | 9,292.00 | 9,396.00 |
| 32 | 7,165.67 | 7,308.00 | 7,497.00 | 8,130.00 |
| 64 | 5,406.00 | 5,968.00 | 5,965.33 | 6,144.67 |
| 128 | 3,707.00 | 3,728.33 | 3,857.33 | 4,960.67 |
微妙ですね。
同時スレッド2,4,8だけでグラフにするとこんな感じです。
innodb_thread_concurrency=2の場合
同時スレッド2と4が性能が良い、同時スレッドを上げると急激に性能低下
innodb_thread_concurrency=4の場合
同時スレッド2と4が性能が良い、同時スレッドを上げると時の落ち方がinnodb_thread_concurrency=2の場合より少し緩やか
innodb_thread_concurrency=8の場合
同時スレッド4が他より性能が良い、同時スレッドを上げると時の落ち方がinnodb_thread_concurrency=2の場合より少し緩やか
innodb_thread_concurrency=20(無制限を意味する)の場合
同時スレッド8に比べてピーク性能が落ちる 同時スレッドを上げると時の落ち方が他と比べて緩やか
といったところが特徴でしょう。
OSDL DBT-1 (ODBC版) による MySQL 5.0 性能測定 CPU 構成の差異による特性の分析と考察 Intel Xeon デュアルコア編 で、「最大スレッド数を無制限にすることで 10% 程度性能を上げることができた」のは、マシンスペックの問題でしょう。
あちらは
CPU: AMD Opteron 254 x 2 (2.8GHz, AMD64, L2 1MB)
Memory: 8GB (DDR/400, ECC)
Storage: 73GB (RAID1, 73GB x 2, SAS, 10000rpm, 2.5inch)
特徴:
シングルコア Opteron の最上位版 (2006年3月現在)
AMD64 (x86-64) 対応
SAS (Serial Attached SCSI) 接続で2.5インチのハードディスク
ですから、同時処理性能が高いためだと思います。
innodb_thread_concurrencyについてまとめると
・同時処理性能に影響はある
・CPUのコア数とディスク性能によって、設定値を決めるべき
・一般的なサーバ機(今時の1CPUデュアルコア以上+RAID)で、MySQL 5.0.8 以上ならば初期値の20でほぼ問題ないと思われる
・レベルの低いサーバの場合は、より少ない値に設定したほうがよい
・その場合は、CPUのコア数×2か3 くらいが目安になると思われる
ということになると思います。
5月 31