More Related Content
Similar to Sqlアンチパターン(メタデータトリブル) (20)
Sqlアンチパターン(メタデータトリブル)
- 2. マスタ テキストの書式設定• 8.1 目的
• 8.2 アンチパターン
• 8.3 アンチパターンの見つけ方
• 8.4 アンチパターンを用いてもよい場合
• 8.5 解決策
• APPENDIX テストデータトリブル
-1 -
アジェンダ
- 6. マスタ テキストの書式設定<2.データベース管理におけるデメリット>
i. 必要に応じて、新たなメタデータオブジェクトを作成しなくてはならない
(8.2.1 テーブルの増殖)
ii. テーブル定義変更を分割テーブル全てに適用する必要がある。
(8.2.6 メタデータの同期)
iii. テーブルの整合性を管理する為、チェック制約が必要。
(8.2.2 データの整合性を管理する)
iv. 一意性の保証の為に、シーケンスオブジェクトや主キー生成テーブルが必要。
(8.2.4 一意性の保証)
v. 外部キーを定義することができない
(8.2.7 参照性整合性の管理)
-5 -
8.2 アンチパターン:メタデータトリブルのデメリット②
外部キーを定義することができない例
Commentテーブルが子テーブルになる場合、親となるBugsテーブルを複数に分割されており、制約先を単一に指定できな
い為、外部キーを定義することができない。(Commentテーブルも分割すれば外部キーの定義が可能だが・・・)
Bugs_2008
Bugs_2009
Bugs_2010
Comment
- 10. マスタ テキストの書式設定
デメリット:アプリケーション開発
メリット
-9 -
8.5 解決策:①水平パーティショニング(アンチパターンとの比較)
アンチパターンと水平パーティショニング機能の比較結果は以下のとおり。
挿入対象のテーブルを選択しなく
てはならない
分割テーブルを跨いだ検索で
UNIONを使用する必要あり
更新時にテーブル間の移動が必
要なことがある
DB側で処理される為、開発担当者が意
識する必要はない。○×
×
×
テーブル分割単位での検索が高
速化
パーティション分割単位での検索が高
速化○○
アンチパターン(テーブル分割) 水平パーティショニング機能
- 11. マスタ テキストの書式設定
デメリット:データベース管理
-10 -
8.5 解決策:①水平パーティショニング(アンチパターンとの比較)
アンチパターンと水平パーティショニング機能の比較結果は以下のとおり。
必要に応じて、新たなメタデータオ
ブジェクトを作成が必要
テーブル定義変更を分割テーブル
に全てに適用
分割したデータの整合性を管理す
る為、チェック制約が必要
パーティションの追加は必要だが、メタ
データとして管理できる。△×
×
×
アンチパターン(テーブル分割) 水平パーティショニング機能
DB側で処理される為、開発担当者が意
識する必要はない。○
一意性を保証するための仕組みが
必要×
外部キーの定義不可
×
プライマリキー・外部キーの定義により
データ整合性の担保が可能○
- 12. マスタ テキストの書式設定
テストデータ内容
パーティション分割なしのテーブルBugsとパーティション分割ありのテーブルBugs_Pを作成し、同一のテスト
データを挿入。(データベース Oracle DB 11g R1を使用)
-11 -
8.5 解決策:①水平パーティショニング(パフォーマンス検証:準備)
パーティション無しのテーブルとパーティション有りのテーブルを用意し、それぞれ同一の
レコードを挿入し、クエリ実行時間の検証を行った。
Bugs_P
※DATE_REPORTEDによる分割
P2010
P2009
P2008
Bugs
テーブル パーティション DATE_REPORTED レコード件数 容量(M)
2008/1/1 ~ 12/31 5,602,727
2009/1/1 ~ 12/31 5,587,420
2010/1/1 ~ 12/31 5,587,069
P2008 2008/1/1 ~ 12/31 5,602,727 488.0
P2009 2009/1/1 ~ 12/31 5,587,420 480.0
P2010 2010/1/1 ~ 12/31 5,587,069 480.0
BUGS_P
BUGS 無し 1,472.0
- 13. マスタ テキストの書式設定
パーティショニングありの場合
パーティショニングなしの場合
-12 -
8.5 解決策:①水平パーティショニング(パフォーマンス検証:検索)
2010年に発生したバグの対応時間の合計取得するSQLを実行し、所要時間を比較。
-- SQL:2010年に発生したバグの対応時間の合計取得
SELECT SUM(HOURS) FROM BUGS WHERE DATE_REPORTED BETWEEN
TO_DATE('2010-01-01', 'YYYY-MM-DD') AND TO_DATE('2010-12-31', 'YYYY-MM-DD');
-- 実行計画
SELECT STATEMENT Cost = 50199
SORT AGGREGATE
TABLE ACCESS FULL BUGS
-- 実行結果
1件選択されました(9796 msec.)
→ 約10秒
-- SQL:2010年に発生したバグの対応時間の合計取得
SELECT SUM(HOURS) FROM BUGS_P WHERE DATE_REPORTED BETWEEN
TO_DATE('2010-01-01', 'YYYY-MM-DD') AND TO_DATE('2010-12-31', 'YYYY-MM-DD');
-- 実行計画
SELECT STATEMENT Cost = 16759
SORT AGGREGATE
PARTITION RANGE SINGLE
TABLE ACCESS FULL BUGS_P
-- 実行結果
1件選択されました(3744 msec.)
→ 約4秒
パーティショニングありの方が、早い!
- 14. マスタ テキストの書式設定
パーティショニングありの場合
パーティショニングなしの場合
-13 -
8.5 解決策:①水平パーティショニング(パフォーマンス検証:削除)
2008年に発生したバグのレコードを削除するSQLを実行し、所要時間を比較。
-- SQL:2008年のレコードを削除
DELETE FROM BUGS WHERE DATE_REPORTED BETWEEN
TO_DATE('2008-01-01', 'YYYY-MM-DD') AND TO_DATE('2008-12-31', 'YYYY-MM-DD');
-- 実行計画
DELETE STATEMENT Cost = 50152
DELETE BUGS
TABLE ACCESS FULL BUGS
-- 実行結果
5602727行削除されました(516862 msec.)
→ 約8分
-- SQL:2008年のレコードを削除
ALTER TABLE BUGS_P DROP PARTITION P2008;
-- 実行結果
表が変更されました(296 msec.)
→ 1秒未満
※DELETEの場合は使用領域が解放されない。また、HWMも下がらない為、クエリの実行速度も改善されない。
-13 -
削除前 削除後
SEGMENT_NAME PARTITION_NAME MBYTES SEGMENT_NAME PARTITION_NAME MBYTES
BUGS 1472 BUGS 1472
BUGS_P P2008 488
BUGS_P P2009 480 BUGS_P P2009 480
BUGS_P P2010 480 BUGS_P P2010 480
パーティショニングありの方が、早い!
- 15. マスタ テキストの書式設定
パーティショニングありの場合
パーティショニングなしの場合
-14 -
8.5 解決策:①水平パーティショニング(パフォーマンス検証:全期間検索)
全期間のバグの対応時間の合計を取得するSQLを実行し、所要時間を比較。
-- SQL:全期間のバグの所要時間の合計を算出
SELECT SUM(HOURS) FROM BUGS;
-- 実行計画
SELECT STATEMENT Cost = 50241
SORT AGGREGATE
TABLE ACCESS FULL BUGS
-- 実行結果
1件選択されました(9079 msec.)
→ 約9秒
-- SQL:全期間のバグの所要時間の合計を算出
SELECT SUM(HOURS) FROM BUGS_P;
-- 実行計画
SELECT STATEMENT Cost = 50246
SORT AGGREGATE
PARTITION RANGE ALL
TABLE ACCESS FULL BUGS_P
-- 実行結果
1件選択されました(11326 msec.)
→ 約11秒
パーティション分割を行う場合、効果的なパーティションキーを設定する必要がある。
(①画面からの検索条件、②バッチでの集計条件、③データパージ単位等が候補となる)
パーティショニングありの方が、遅い!
- 16. マスタ テキストの書式設定
例1.サイズが大きい列を切り離す
*(アスタリスク)を用いた検索にてサイズの大きいデータの取得を回避する為、別テーブルに切り離す。
-15 -
8.5 解決策:②垂直パーティショニング
列でのテーブルを分割をする垂直パーティショニングは、列の一部のサイズが大きい場
合や、めったに使用されない場合にメリットがある。
例2.固定長と可変長の列を切り離す
MySQLのMyISAMストレージエンジンで検索を効率化する為、可変長の列を別テーブルに切り離す。
Products
product_id product_name ・・・ installer_image
P0001 product1 ・・・ ※バイナリデータ
P0002 product2 ・・・ ※バイナリデータ
Products
product_id product_name ・・・
P0001 product1 ・・・
P0002 product2 ・・・
Bugs
bug_id summary date_reported description resolution
P0001 固定長 固定長 可変長 可変長
Bugs
bug_id summary date_reported
P0001 固定長 固定長
bug_id description resolution
P0001 可変長 可変長
BugDescriptions
ProductInstallers
product_id installer_image
P0001 ※バイナリデータ
P0002 ※バイナリデータ
- 18. マスタ テキストの書式設定
-17 -
APPENDIX:テストデータトリブル
SELECT - INSERTを繰り返すことにより、2のn乗(nは繰り返し回数)のテストデータを作成する。
BEGIN
-- 【1.ベースとなるレコードを1件のみINSERT】
INSERT INTO BUGS
(BUG_ID, DATE_REPORTED, SUMMARY, DESCRIPTION, RESOLUTION, REPORTED_BY, ASSIGNED_TO, VERIFIED_BY, STATUS, PRIORITY, HOURS)
VALUES
(1, TO_DATE('2008/01/01', 'YYYY/MM/DD'), 'SUMMARY', 'DESCRIPTION', 'RESOLUTION', 1, 1, 1, 'Completed', 'Middle', 10) ;
COMMIT;
-- 【2.SELECT–INSERTを繰り返す】
-- 2^24 = 16,777,216件を生成
FOR i IN 1..24 LOOP
INSERT /*+ APPEND */ INTO
BUGS
SELECT
-- BUG_ID:INSERT完了件数 2^(i-1) + ROWNUMにより、1からの連番とする。
POWER(2, i - 1) + ROWNUM
-- DATE_REPORTED:2008/1/1 ~ 2010/12/31 に振り分ける
,TO_DATE(‘2008/01/01’, ‘YYYY/MM/DD’) + (MOD(POWER(2, i - 1) + ROWNUM, 1096))
,(省略)
FROM
BUGS
;
COMMIT;
END LOOP;
END;
/
PL/SQLが実行されました(63227 msec.)
--------------------------------------------------------------------------------