使用IFNULL会阻止SQLite使用索引吗?

时间:2014-04-02 13:12:28

标签: android sql sqlite indexing

假设我有一个表T和一个关于字段f的索引。我想根据某个整数f过滤myF。如果整数为0,我想要fnull的所有记录。写这个的可靠方法是:

db.rawQuery("SELECT someField FROM T WHERE "
        + (myF == 0 ? "f IS NULL" : "f = ?"),
        (myF == 0 ? new String[] {}, new String[] {String.valueOf(myF)}));

这有点不方便;特别是如果查询比这更复杂并且有其他参数。所以我以为我会写

db.rawQuery("SELECT someField FROM T WHERE IFNULL(f, 0) = ?", 
        new String[] {String.valueOf(myF)});
相反,它更简单,更易于阅读,更易于维护.¹

我的问题是:如果f上有索引,SQLite是否仍会使用该索引,还是会采用表扫描?我问,因为在后一种情况下我不是比较一个字段和一个参数,而是一个表达式和一个参数,我不确定SQLite查询优化器是多么“聪明”。


¹请注意,数据库中没有f = 0的记录。

1 个答案:

答案 0 :(得分:4)

这将导致表扫描。

使用sqlite3命令行客户端的示例:

sqlite> create table t(f);
sqlite> create index tf on t(f);
sqlite> explain query plan select * from t where ifnull(f,0)=1;
0|0|0|SCAN TABLE t (~500000 rows)
sqlite> explain query plan select * from t where f is null;
0|0|0|SEARCH TABLE t USING COVERING INDEX tf (f=?) (~10 rows)
sqlite> explain query plan select * from t where f=1;
0|0|0|SEARCH TABLE t USING COVERING INDEX tf (f=?) (~10 rows)