sqlアンチパターンnight ライトニングトーク

39
SQL アアアアアアア Night アアアアアアアアア アアアアアアアアアア アアアア 2015/04/10

Upload: itabashi-masayuki

Post on 30-Jul-2015

575 views

Category:

Engineering


0 download

TRANSCRIPT

Page 1: SQLアンチパターンNight ライトニングトーク

SQL アンチパターン Nightライトニングトーク

株式会社ヴァル研究所板橋正之2015/04/10

Page 2: SQLアンチパターンNight ライトニングトーク

自己紹介■ 名前

板橋 正之(いたばし まさゆき)

■ 所属株式会社ヴァル研究所JAWS-UG 中央線

■ 仕事自社広告配信サーバの開発、運用

■ 好きな RDBMSOracle Database

itabashi.masayuki

Page 3: SQLアンチパターンNight ライトニングトーク

今日は SQL アンチパターン Night ということで

失敗談を持ってきました。

Page 4: SQLアンチパターンNight ライトニングトーク

今から 5 年ぐらい前の案件です。

Page 5: SQLアンチパターンNight ライトニングトーク

13 時間程度で終了すると思った3,500 万件弱のデータ洗い替え作業が

5 日以上掛かった

失敗談

Page 6: SQLアンチパターンNight ライトニングトーク

某システムの会員情報の ID 変更

案件

Page 7: SQLアンチパターンNight ライトニングトーク

テーブルイメージ

Page 8: SQLアンチパターンNight ライトニングトーク

単純に UPDATE 文の羅列で古い会員コードを

一旦テンポラリコードに編集してその後、新しい会員コードに振り直す。

やったこと

Page 9: SQLアンチパターンNight ライトニングトーク

会員コードは主キーの一部でインデックスが設定されているので更新時にはインデックス書き換えの

オーバーヘッドを減らすためインデックスを解除した。

検討事項

Page 10: SQLアンチパターンNight ライトニングトーク

更新が多くなる分、 UNDO 表領域、 REDO ログファイルを作成されることも予想されるため、ディスクを節約したかった。

検討事項

Page 11: SQLアンチパターンNight ライトニングトーク

• テスト環境でサンプルのテーブルを使ってインデックスあり、なしの時間を計測して、処理時間を見積もりました。• テーブル A: 448,251件

• テーブル B: 561,018件

• アーカイブ REDOログによるディスク使用量もテーブル Aが1,062MB/556MB、テーブル Bが 1,821MB/607MBと計測しました。

• 上記の結果からインデックスなしの方が明らかに処理時間が短いことから、インデックスなしで処理を行なう方がよいと判断しました。

処理時間見積り

操作内容 時間 合計インデックスあ

りテンポラリ会員コード更新 0:06:48

0:18:37新会員コード更新 0:11:49

インデックスなし

インデックス無効 & テンポラリ会員コード更新

0:01:090:09:23

新会員コード更新 0:07:20

インデックス再作成 0:00:54

操作内容 時間 合計インデックスあ

りテンポラリ会員コード更新 0:09:24

0:33:28新会員コード更新 0:24:04

インデックスなし

インデックス無効 & テンポラリ会員コード更新

0:01:150:09:05

新会員コード更新 0:06:48

インデックス再作成 0:01:02

Page 12: SQLアンチパターンNight ライトニングトーク

• 更新対象データが 34,971,205 件• 検証データが 448,251 件で 10 分弱• 34,971,205÷448,251×10 780≒ 分

= 13 時間

Page 13: SQLアンチパターンNight ライトニングトーク

大間違い

Page 14: SQLアンチパターンNight ライトニングトーク

サンプリングが少ない。

Page 15: SQLアンチパターンNight ライトニングトーク

• 2 テーブル程度のデータで信頼性のある値がだせるのか?

• 見積もりを行なったテーブルは、比較的データ件数が近い。

Page 16: SQLアンチパターンNight ライトニングトーク

データ件数と処理時間の相関関係を見出していない。

Page 17: SQLアンチパターンNight ライトニングトーク

本番サーバの方が性能いい?

Page 18: SQLアンチパターンNight ライトニングトーク

(当時でも)もう 5 年前のサーバだよ?

Page 19: SQLアンチパターンNight ライトニングトーク

思い込みと楽観視

Page 20: SQLアンチパターンNight ライトニングトーク

まず、テンポラリ会員コードへの更新

テーブル データ件数

  更新(秒 ) 

 更新(分 ) 

  1万件当たりの秒数 

会員マスタ 69,322 3.063 0.1 0.4419

会員所属マスタ 61,543 14.047 0.2 2.2825

受付テーブル 159,330 26.454 0.4 1.6603

予約テーブル 159,330 16.313 0.3 1.0239

ヘッダーテーブル 159,330 13.125 0.2 0.8238

コーステーブル 159,330 73.75 1.2 4.6288

明細テーブル A 8,564,614 609.703 10.2 0.7119

明細テーブル B 454,350 23.204 0.4 0.5107

明細テーブル C 17,845,016 1721.546 28.7 0.9647

明細テーブル D 2,668,722 179.672 3.0 0.6733

明細テーブル E 1,193,156 249.61 4.2 2.0920

明細パラメータテーブル 159,329 46.453 0.8 2.9155

明細付加情報テーブル 360,250 33.515 0.6 0.9303

印刷集計管理テーブル 335,480 68.75 1.1 2.0493

印刷履歴テーブル 1,545,991 599.188 10.0 3.8757

ワークフロー履歴テーブル 910,836 188.672 3.1 2.0714

ワークフロー制御テーブル 1,285,598 826.844 13.8 6.4315

洗い替え開始

SQL> SET TRANSACTION READ WRITE;SQL> UPDATE 会員マスタ SQL> SET 会員コード = ‘X’ || 会員コード ;SQL> COMMIT;

すでに更新秒数にバラツキがっ!

Page 21: SQLアンチパターンNight ライトニングトーク

続いて新しい会員コードへの更新洗い替え開始

SQL> SET TRANSACTION READ WRITE;SQL> UPDATE 会員マスタ SQL> SET 会員コード = ‘2157’SQL> WHERE ( 会員コード = ‘X1356’);SQL> UPDATE 会員マスタ SQL> SET 会員コード = ‘3952’SQL> WHERE ( 会員コード = ‘X65165’);SQL> UPDATE 会員マスタ SQL> SET 会員コード = ‘4510’SQL> WHERE ( 会員コード = ‘X2157’);SQL> ・・・SQL> COMMIT;

Page 22: SQLアンチパターンNight ライトニングトーク

続いて新しい会員コードへの更新洗い替え開始

SQL> SET TRANSACTION READ WRITE;SQL> UPDATE 会員マスタ SQL> SET 会員コード = ‘2157’SQL> WHERE ( 会員コード = ‘X1356’);SQL> UPDATE 会員マスタ SQL> SET 会員コード = ‘3952’SQL> WHERE ( 会員コード = ‘X65165’);SQL> UPDATE 会員マスタ SQL> SET 会員コード = ‘4510’SQL> WHERE ( 会員コード = ‘X2157’);SQL> ・・・SQL> COMMIT;

テーブル データ件数 更新 (分 )   1万件当たりの秒数 

会員マスタ 69,322 約 7 分 60.5868

会員所属マスタ 61,543 約 10 分 97.4928

受付テーブル 159,330 約 64 分 241.0092

予約テーブル 159,330 約 140 分 527.2077

ヘッダーテーブル 159,330 約 60 分 225.9461

コーステーブル 159,330 約 65 分 244.7750

明細テーブル A 8,564,614

明細テーブル B 454,350

明細テーブル C 17,845,016

明細テーブル D 2,668,722

明細テーブル E 1,193,156

明細パラメータテーブル 159,329 約 96 分 361.5161

明細付加情報テーブル 360,250 約 900分 1498.9590

印刷集計管理テーブル 335,480 約 70 分 125.1938

印刷履歴テーブル 1,545,991

ワークフロー履歴テーブル 910,836

ワークフロー制御テーブル 1,285,598

Page 23: SQLアンチパターンNight ライトニングトーク

• 金曜の夜にテンポラリ会員コードへの更新を行って、土日で新会員コードへの洗い替えをやっていて日曜日の 23:00 くらいにこんな感じでしたね。

• 直後にお詫びのメールを送って翌日朝一でお詫びの電話しました。

• この時点で更新のオーバーヘッドより、更新対象検索のオーバーヘッドが大きいと判断して、いくつかのサンプリングで確認した結果、無効にしていたインデックスを有効にして更新を行なうこととしました。

Page 24: SQLアンチパターンNight ライトニングトーク

• 土日で終了しなかったので月曜日は当該年度のデータのみを更新、この時点でインデックスを復活。当然、この日はサービス停止。テーブル データ件数 更新 (分 )

  1万件当たりの秒数 

会員マスタ 69,322 約 7 分 60.5868

会員所属マスタ 61,543 約 10 分 97.4928

受付テーブル 159,330 約 64 分 241.0092

予約テーブル 159,330 約 140 分 527.2077

ヘッダーテーブル 159,330 約 60 分 225.9461

コーステーブル 159,330 約 65 分 244.7750

明細テーブル A 854,569 20 分 46 秒 14.5805

明細テーブル B 44,081 約 90 分 1225.0176

明細テーブル C 1,770,240 36 分 6 秒 12.2356

明細テーブル D 360,356 約 910 分 1515.1683

明細テーブル E 162,150 約 47 分 173.9130

明細パラメータテーブル 159,329 約 96 分 361.5161

明細付加情報テーブル 360,250 約 900 分 1498.9590

印刷集計管理テーブル 335,480 約 70 分 125.1938

印刷履歴テーブル 124,474 約 38 分 183.1708

ワークフロー履歴テーブル 157,888 約 92 分 349.6149

ワークフロー制御テーブル 131,976 約 48 分 218.2215

Page 25: SQLアンチパターンNight ライトニングトーク

テーブル データ件数 更新 (分 )  1万件当たりの秒

数 会員マスタ 69,322 約 7 分 60.5868

会員所属マスタ 61,543 約 10 分 97.4928

受付テーブル 159,330 約 64 分 241.0092

予約テーブル 159,330 約 140 分 527.2077

ヘッダーテーブル 159,330 約 60 分 225.9461

コーステーブル 159,330 約 65 分 244.7750

明細テーブル A854,569

7,710,04520 分 46 秒

3 時間 28 分 56 秒14.580516.2593

明細テーブル B44,081

410,269約 90 分

1 時間 39 分 14 秒1225.0176

145.1242

明細テーブル C1,770,240

16,074,77636 分 6 秒

5 時間 22 分 29 秒12.235612.0368

明細テーブル D360,356

2,308,366約 910 分

1 時間 20 分 3 秒1515.168320.8069

明細テーブル E162,150

1,031,006約 47 分

1 時間 27 分 13 秒173.913050.7562

明細パラメータテーブル 159,329 約 96 分 361.5161

明細付加情報テーブル 360,250 約 900 分 1498.9590

印刷集計管理テーブル 335,480 約 70 分 125.1938

印刷履歴テーブル 124,4741,421,517

約 38 分26 時間 20 分 5 秒

183.1708666.9283

ワークフロー履歴テーブル 157,888752,948

約 92 分11 時間 20 分 43 秒

349.6149542.4412

ワークフロー制御テーブル 131,9761,153,622

約 48 分20 時間 10 分 21 秒

218.2215629.5043

残りも更新

Page 26: SQLアンチパターンNight ライトニングトーク

原因は?

Page 27: SQLアンチパターンNight ライトニングトーク

エクステントの分断化?

Page 28: SQLアンチパターンNight ライトニングトーク

インデックスの更新にはオーバーヘッドがかかるという思い込み

Page 29: SQLアンチパターンNight ライトニングトーク

ある件数を超えるとインデックス更新のオーバーヘッドより全表検索のオー

バーヘッドが大きくなる

全表検索+データ更新 < インデックス検索+データ更新+インデックス更新

全表検索+データ更新 > インデックス検索+データ更新+インデックス更新

データの件数が一定数を超えると

Page 30: SQLアンチパターンNight ライトニングトーク

インデックスの構造

Page 31: SQLアンチパターンNight ライトニングトーク

年次単位での参照が多いため年月日、会員コードの順番で複合インデックスが作られていた

Page 32: SQLアンチパターンNight ライトニングトーク

• 余計なアクセスパスが多い• 一部のテーブルは年月日と会員 ID の順番が逆でインデックスが生成されていており、実際そちらの方がパフォーマンスがよかった。

• 正確にいうとマルチテナントのシステムだったので年月日の上にさらにコードがあった。

Page 33: SQLアンチパターンNight ライトニングトーク

UPDATE 文 1 行 1 行流すんじゃなくて変換テーブルとの JOIN で更新するよう

なUPDATE 文で更新する方法も

あったんじゃないかと。

Page 34: SQLアンチパターンNight ライトニングトーク

(先にあげた原因を解決するのはもちろんとして)

今後の反省として

Page 35: SQLアンチパターンNight ライトニングトーク

自然キーもいいけど疑似キーもね

Page 36: SQLアンチパターンNight ライトニングトーク
Page 37: SQLアンチパターンNight ライトニングトーク

最近だったらクラウド環境で停止時間を最小限に

Page 38: SQLアンチパターンNight ライトニングトーク

• 例えば別のインスタンスをスナップショット等から作成して、そちらを更新後に差分を適用するなど。

• 見積もりも本番と同じ環境でできるし。• 昔と違って DB のコピーを(お金はかかり

ますが)ポコポコ立てられる時代になったので。

Page 39: SQLアンチパターンNight ライトニングトーク

以上、ご清聴ありがとうございました。