AndroidでSQLiteのパフォーマンス比較(DELETE編)

前回の[INSERT編](http://qiita.com/alzybaad/items/b350b49740a3d25297c1)に続き、今回はDELETE編。

#### 環境
Nexus5, Android 4.4.4

#### テーブル
こんなかんじ。深い意味はない。

|カラム名|型|制約|
|:--|:--|:--|
|id|TEXT|PRIMARY KEY|
|name|TEXT|NOT NULL|
|address|TEXT||
|count|INTEGER|NOT NULL|
|flag|INTEGER|NOT NULL|

#### INSERT済みのデータ
前回のINSERT編でINSERTした以下のようなデータ10000件。

|id|name|address|count|flag|
|:--|:--|:--|:--|:--|
|id0|name0|NULL|0|0|
|id1|name1|NULL|1|0|
|id2|name2|NULL|2|0|
|...|...|...|...|...|
|id9999|name9999|NULL|9999|0|

#### 使用メソッド
今回比較したメソッドは以下の3つ。

- `SQLiteDatabase#delete`
- `SQLiteDatabase#execSQL`
- `SQLiteStatement#executeUpdateDelete`

#### 1行削除
1行(`id`=`id5000`)をそれぞれのメソッドでDELETEする。

###### **SQLiteDatabase#delete**
Androidで一般的な方法。SQLを知らなくても書ける。

```java
db.beginTransaction();
try {
    db.delete("table_name", "id=?", new String[]{"id5000"});
    db.setTransactionSuccessful();
} finally {
    db.endTransaction();
}
```
###### **SQLiteDatabase#execSQL**
SQLを知っていれば、こちらの方が書きやすい。ただし、戻り値はなし。

```java
db.beginTransaction();
try {
    db.execSQL("DELETE FROM table_name WHERE id=?", new String[]{"id5000"});
    db.setTransactionSuccessful();
} finally {
    db.endTransaction();
}
```
###### **SQLiteStatement#executeUpdateDelete**
Android3.0から追加された方法。INSERTはこれが一番速かった。

```java
db.beginTransaction();
try {
    final SQLiteStatement statement = db.compileStatement("DELETE FROM table_name WHERE id=?");
    try {
        statement.bindString(1, "id5000");
        statement.executeUpdateDelete();
    } finally {
        statement.close();
    }
    db.setTransactionSuccessful();
} finally {
    db.endTransaction();
}
```
###### **結果**
結果は以下の通り。1行なので`SQLiteStatement`も効果はない。

|メソッド|処理時間(msec)|
|:--|:--|
|`SQLiteDatabase#delete`|8.75|
|`SQLiteDatabase#execSQL`|8.92|
|`SQLiteStatement#executeUpdateDelete`|8.69|

ちなみに、PRIMARY KEYでない`name`を条件にした場合は以下の通りで当然いずれも遅くなる。

|メソッド|処理時間(msec)|
|:--|:--|
|`SQLiteDatabase#delete`|13.71|
|`SQLiteDatabase#execSQL`|13.55|
|`SQLiteStatement#executeUpdateDelete`|13.49|

#### 複数行削除
それぞれのメソッドでN(=1, 5, 10, 50, 100)行ずつ、M(=100, 1000)行DELETEする。
以降のソースはN=5, M=1000の場合。

###### **SQLiteDatabase#delete**

```java
db.beginTransaction();
try {
    final String whereClause = "id IN (?,?,?,?,?)";
    final String[] whereArgs = new String[count];
    for (int i = 0, index = 0; i < 10000; i += 10) {
        whereArgs[index++] = "id" + i;
        if (index == 5) {
            db.delete("table_name", whereClause, whereArgs);
            index = 0;
        }
    }
    db.setTransactionSuccessful();
} finally {
    db.endTransaction();
}
```
###### **SQLiteDatabase#execSQL**

```java
db.beginTransaction();
try {
    final String sql = "DELETE FROM table_name WHERE id IN (?,?,?,?,?)";
    final String[] bindArgs = new String[count];
    for (int i = 0, index = 0; i < 10000; i += 10) {
        bindArgs[index++] = "id" + i;
        if (index == 5) {
            db.execSQL(sql, bindArgs);
            index = 0;
        }
    }
    db.setTransactionSuccessful();
} finally {
    db.endTransaction();
}
```
###### **SQLiteStatement#executeUpdateDelete**

```java
db.beginTransaction();
try {
    final SQLiteStatement statement = db.compileStatement("DELETE FROM table_name WHERE id IN (?,?,?,?,?)");
    try {
        for (int i = 0, index = 0; i < 10000; i += 10) {
            statement.bindString(++index, "id" + i);
            if (index == 5) {
                statement.executeUpdateDelete();
                index = 0;
            }
        }
    } finally {
        statement.close();
    }
    db.setTransactionSuccessful();
} finally {
    db.endTransaction();
}
```

###### **結果**
結果は以下の通り。
M=100の場合はN<=5、M=1000の場合はN<=10までは`SQLiteStatement#executeUpdateDelete`が速いが、それ以降からどれも変わらなくなる。
100行程度であれば、どのメソッドでも1度に100行DELETEしてよさそう。
それ以上であれば、`SQLiteStatement`で10〜50行程度ずつDELETEするのがベスト？

|N|メソッド|M=100|M=1000|
|:--|:--|:--|:--|
|1|`SQLiteDatabase#delete`|72.14|258.83|
||`SQLiteDatabase#execSQL`|73.09|238.73|
||`SQLiteStatement#executeUpdateDelete`|**56.50**|**184.08**|
|5|`SQLiteDatabase#delete`|55.18|126.14|
||`SQLiteDatabase#execSQL`|53.03|84.25|
||`SQLiteStatement#executeUpdateDelete`|**50.71**|**74.06**|
|10|`SQLiteDatabase#delete`|**47.86**|111.01|
||`SQLiteDatabase#execSQL`|49.66|107.33|
||`SQLiteStatement#executeUpdateDelete`|48.88|**79.59**|
|50|`SQLiteDatabase#delete`|**46.80**|**77.18**|
||`SQLiteDatabase#execSQL`|48.83|82.33|
||`SQLiteStatement#executeUpdateDelete`|46.20|79.67|
|100|`SQLiteDatabase#delete`|**47.43**|95.91|
||`SQLiteDatabase#execSQL`|48.79|**92.67**|
||`SQLiteStatement#executeUpdateDelete`|49.78|94.60|