#動機
SQLiteを使ったAndroidアプリを開発している。
日々積み上がるデータを集計する必要があり、長期間の運用に耐えうるパフォーマンスが得られるか検証してみた。
#評価対象
実プロジェクト用の検証なので、そのままのコードは晒せないがデータ構造は以下の様になる。Int,Long,BooleanはINTEGER型としてStringはTEXT型として対応するテーブルを作成している。
class Record{
var num1 : Int = 0
var num2 : Int = 0
var date : Long = 0 // ★ INDEXを作成している
var num3: Int = 0
var num4: Int = 0
var num5: Int = 0
var num6 : Int = 0
var amount : Long = 0
var num7 : Int = 0
var text1 : String = ""
var text2: String = ""
var num8 : Int = 0
var num9 : Int = 0
var flag1 : Boolean = false
}
#評価方法
1日30件ほど積み上がるデータを20年間蓄積した場合、年単位の集計をどの程度の時間でこなせるかを評価したい。
またSELECTを使った場合とSUMを使った場合の性能の違いも確認してみたい。
行った試験は以下の4パターン
-
SUMで年単位で集計
-
SUMで全期間(20年)で集計
-
SELECTで年単位で集計
-
SELECTで全期間(20年)で集計
※SUNを使った集計はSUM(amount)としてSQLを発行している。
※SELECTを使った集計はRecord中のamount:Longのみ取り出して加算している。
※年単位のデータ数は10,950件、20年分だと219,000件になる。
Log.i("test", "---- select test (per year) ----")
var totalMS:Long = 0
for(year in 2000..(2000+(years-1))) {
val range = DateRange(DateEx(year,1,1), DateEx(year+1,1,1))
val t1 = Date().time
var sum = sumBySelect()
val t2 = Date().time
Log.i("test", "year${year} sum:${sum} time:${t2-t1}ms")
totalMS += (t2-t1)
}
Log.i("test","select total:${totalMS}ms")
Log.i("test", "---- select test (all year) ----")
val range = DateRange(DateEx(2000,1,1), DateEx(2000+years,1,1))
val t1 = Date().time
var sum = sumBySelect()
val t2 = Date().time
Log.i("test", "select all year sum:${sum} time:${t2-t1}ms")
#試験環境
評価にはHUAWEI P20 lite (Android9)を使用した。
AndroidStudioからデバッグモードでリモート実行しているので、リリース版を実機にインストールして評価すればもっと良い結果が得られると思う。
#試験結果
---- SUM (per year) ----
year:2000 sum:10950000 time:21ms
year:2001 sum:10950000 time:20ms
year:2002 sum:10950000 time:19ms
year:2003 sum:10950000 time:20ms
year:2004 sum:10950000 time:19ms
year:2005 sum:10950000 time:19ms
year:2006 sum:10950000 time:20ms
year:2007 sum:10950000 time:20ms
year:2008 sum:10950000 time:20ms
year:2009 sum:10950000 time:19ms
year:2010 sum:10950000 time:20ms
year:2011 sum:10950000 time:19ms
year:2012 sum:10950000 time:19ms
year:2013 sum:10950000 time:20ms
year:2014 sum:10950000 time:19ms
year:2015 sum:10950000 time:20ms
year:2016 sum:10950000 time:19ms
year:2017 sum:10950000 time:19ms
year:2018 sum:10950000 time:19ms
year:2019 sum:10950000 time:19ms
totalMS:390ms
---- SUM (all year) ----
all year: sum:219000000 time:348ms
---- SELECT (per year) ----
year:2000 sum:10950000 time:195ms
year:2001 sum:10950000 time:35ms
year:2002 sum:10950000 time:35ms
year:2003 sum:10950000 time:37ms
year:2004 sum:10950000 time:36ms
year:2005 sum:10950000 time:36ms
year:2006 sum:10950000 time:36ms
year:2007 sum:10950000 time:36ms
year:2008 sum:10950000 time:35ms
year:2009 sum:10950000 time:35ms
year:2010 sum:10950000 time:36ms
year:2011 sum:10950000 time:35ms
year:2012 sum:10950000 time:36ms
year:2013 sum:10950000 time:36ms
year:2014 sum:10950000 time:35ms
year:2015 sum:10950000 time:36ms
year:2016 sum:10950000 time:35ms
year:2017 sum:10950000 time:36ms
year:2018 sum:10950000 time:35ms
year:2019 sum:10950000 time:34ms
totalMS:870ms
---- SELECT (all year) ----
select all year: sum:219000000 time:5596ms
#考察
SUMについては20年間運用しても実用的なパフォーマンスで集計できることが分かった。
両者を比較するとSELECTはSUMに対して1.8倍程度時間(初回除く)がかかっている。初回は10倍程度の処理時間になる。
またSELECTを使って全期間を集計した場合、年単位で集計したものを合計した時間より遥かに長い時間(6倍)がかかっている。これは推測だが全レコードを収容するResultSetをメモリ上に確保するのに時間を要するのかもしれない。