裏MySQL MySQLでサンプリング あれこれ
MySQLでビックデータを扱う場合、データをサンプリングしたいことがある。MS-SQL Serverなどではサンプリング関数が用意されているが、MySQLにはない。
SELECT * FROM report ORDER BY RAND() LIMIT 5
と単純にクエリを書くこともできるが、ビックデータでこれをやるとMySQLがfilesortで死んでしまう。
SELECT * FROM `report` rp, (SELECT ROUND(RAND()*@max) as report_id FROM `report`, (SELECT @max:=AUTO_INCREMENT FROM information_schema.tables WHERE TABLE_SCHEMA=database() AND TABLE_NAME='report' ) setup LIMIT 5 -- サンプリング数 ) rs WHERE rp.report_id=rs.report_id
そこで、プライマリキーがあってかつ、auto_incrementが設定されている場合は上のようにプライマリキーのMAX値を取ってきてその範囲内でランダムな値を生成するようにする。
ただし、これも問題があってプライマリキーに歯抜けや、auto_index値がおかしな値だった場合にうまくサンプルできない。auto_increment値が存在するレコードのプライマリキーのMAX値を超えている場合は以下のようにリセットする必要がある。
SET @MAX:=(SELECT MAX(report_id) FROM report)+1; SET @SQL=CONCAT('ALTER TABLE report AUTO_INCREMENT = ',@MAX); PREPARE init_auto_inc FROM @SQL; EXECUTE init_auto_inc ;
SELECT * FROM `report` rp, (SELECT @report_id:=@report_id+CEIL(RAND()*@max/5) as report_id FROM `report`, (SELECT @max:=report_id,@report_id:=0 FROM report ORDER BY report_id desc LIMIT 1 ) setup LIMIT 5 ) rs WHERE rp.report_id=rs.report_id