假设我有一个表T
和一个关于字段f
的索引。我想根据某个整数f
过滤myF
。如果整数为0,我想要f
为null
的所有记录。写这个的可靠方法是:
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
的记录。
答案 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)