SQLアンチパターン読書会 15章 ランダムセレクション 説明資料

14
15章 ランダムセレクション 2014/02/27(金) SQLアンチパターン読書会 @natsu_nanana

Transcript of SQLアンチパターン読書会 15章 ランダムセレクション 説明資料

Page 1: SQLアンチパターン読書会 15章 ランダムセレクション 説明資料

15章 ランダムセレクション

2014/02/27(金) SQLアンチパターン読書会@natsu_nanana

Page 2: SQLアンチパターン読書会 15章 ランダムセレクション 説明資料

自己紹介

■名前:なつなな(@natsu_nanana)

■仕事:webアプリケーションの開発してます。    最近はソシャゲ案件やってます。

■言語:PHP、JavaScript(jquery)あたりが少々。    最近はshellscript(bash)が楽しいです。

Page 3: SQLアンチパターン読書会 15章 ランダムセレクション 説明資料

本日のパターン

ランダムセレクション

私の中のイメージ

Page 4: SQLアンチパターン読書会 15章 ランダムセレクション 説明資料

利用シーン

■くじ引きで出す景品を複数の中からランダムに選択

■バグ修正担当者を開発チームのメンバーからランダムに選択

■サイトに出す広告を複数の中からランダムに表示

Page 5: SQLアンチパターン読書会 15章 ランダムセレクション 説明資料

アンチパターン

SELECT * FROM Bugs ORDER BY date_reported;

SELECT * FROM Bugs ORDER BY RAND() LIMIT1;

インデックスが効かない!!

(テーブルスキャンが行われる)

■データをランダムにソートする

↑これはランダムにソートをしている

↑これは通常のソート

※余談ですが、「MYSql ランダム」でググるとこのやり方のポストが結構出てきます

Page 6: SQLアンチパターン読書会 15章 ランダムセレクション 説明資料

アンチパターンの見つけ方

■「アプリケーションへのメモリ割当を増やしたいんだけど。

一旦全ての行をアプリケーション上にフェッチしないとランダ

ムに1行を選択できないんだ」

■「一部のエントリは、他に比べて表示される頻度が高いよう

に見える。この乱数発生器は平等に乱数を生成しているのだろ

うか?」

■「SQLは行をランダムに返そうとすると本当に遅くなる」

「ランダムに選択」「乱数が」という言葉が出てくる場合はこのアンチパターンを

疑って良いかと思う

Page 7: SQLアンチパターン読書会 15章 ランダムセレクション 説明資料

アンチパターンを用いても良い場合

データセットが小さい場合※ただし、重み付けが必要な場合等はデータセットが小さくても、適用できません

Page 8: SQLアンチパターン読書会 15章 ランダムセレクション 説明資料

解決策

1.1と最大値の間のランダムなキー値を選択する

 →欠番の穴の後にあるキー値を選択する

2.全てのキー値リストを受け取り、ランダムに一つを選択する

3.オフセットを用いてランダムに行を選択する

4.ベンダー依存の解決策

Page 9: SQLアンチパターン読書会 15章 ランダムセレクション 説明資料

解決策・1欠番のないキー値の場合

1

2

3

4

5

6

7

8

9

10

11

1と最大値(この例だと11)の間の値をランダムに選択する。ランダムに選ばれた値と必ずキー値は必ず一致する

[問題点]

キー値が全て使用されていない(欠番)と

選ばれた値が行と一致しない可能性が発

生する

Page 10: SQLアンチパターン読書会 15章 ランダムセレクション 説明資料

解決策・1欠番のあるキー値の場合

1

2

3

4

5

6

7

8

9

10

11

1から最大値間での間の値をランダムに選択する。ただし、欠番が存在するため、ランダムに選ばれた値と必ずキー値が一致しない場合がある[例]欠番となるキー値4が選択された場合次のキー値5が選択される

[問題点]

キー値5はランダムに選ばれた値が4or5の

場合に選ばれる為、他の値と比べて選択さ

れる頻度が上がる

Page 11: SQLアンチパターン読書会 15章 ランダムセレクション 説明資料

解決策・2キーリストを利用

1

3

6

8

13

14

15

20

23

26

27

最初にキー値のリストを取得する。取得したリストの中からランダムにキー値を選択。その後、選択したキー値を元に対象データを取得

[問題点]

リストが大きいとメモリリソースを超えてエ

ラーとなる

Page 12: SQLアンチパターン読書会 15章 ランダムセレクション 説明資料

解決策・3オフセット値を利用

1

3

6

8

13

14

15

20

23

26

27

COUNT関数を利用して対象データの行数をカウントし、0からカウントした数までの間のランダム値を取得する。データ取得時はその値をオフセット値として使用する。

※oracle、SQLServer、DB2ではrow_number

関数が使えます

SELECT * FROM Bugs LIMIT 1 OFFSET :offset;

SELECT ROUND(RAND() * (SELECT COUNT(*) FROM Bugs))

AS offset;

上で取得したoffset

Page 13: SQLアンチパターン読書会 15章 ランダムセレクション 説明資料

解決策・4ベンダー依存の解決策

■SQL Server2005の場合はTABLESAMPLE句が使える

■Oracleの場合はSAMPLE句が使える

Page 14: SQLアンチパターン読書会 15章 ランダムセレクション 説明資料

以上、説明おわり