通常,SQL索引引用表的列。但是也可以在涉及表列的表达式上形成索引。
例如,请考虑下表跟踪各种“帐户”的美元金额变化
CREATE TABLE account_change( chng_id INTEGER PRIMARY KEY, acct_no INTEGER REFERENCES account, location INTEGER REFERENCES locations, amt INTEGER, -- in cents authority TEXT, comment TEXT);CREATE INDEX acctchng_magnitude ON account_change(acct_no, abs(amt));
account_change表中的每个条目都记录存款或提款到帐户。存款有正数“amt”,提款有负数的“amt”。
acctchng_magnitude索引是超过帐号(“acct_no”)和金额的绝对值。该索引允许对帐户更改的大小进行有效查询。例如,要列出帐号$ xyz的并且存款超过$ 100.00的记录,可以用下列表达式:
SELECT * FROM account_change WHERE acct_no=$xyz AND abs(amt)>=10000;
或者,要按照数量递减的顺序列出对某个特定帐户($ xyz)的所有记录,可以这样:
SELECT * FROM account_change WHERE acct_no=$xyz ORDER BY abs(amt) DESC;
如果没有acctchng_magnitude索引,上述两个示例查询都可以正常工作。acctchng_magnitude索引索引仅帮助查询更快地运行,尤其是在每个帐户的表中有许多条目的数据库上。
使用CREATE INDEX语句在一个或多个表达式上创建新索引,就像在列上创建索引一样。唯一的区别是表达式被列为要索引的元素而不是列名。
当索引的表达式出现在查询的WHERE子句或ORDER BY子句中时,SQLite查询计划程序将考虑在表达式上使用索引,就像在CREATE INDEX语句中编写的那样。查询规划器不执行代数。为了将WHERE子句约束和ORDER BY术语与索引匹配,SQLite要求表达式相同,除了较小的语法差异(如空白更改)。下面是创建的索引:
CREATE TABLE t2(x,y,z);CREATE INDEX t2xy ON t2(x+y);
然后运行查询:
SELECT * FROM t2 WHERE y+x=22;
上面语句是不会使用索引,因为CREATE INDEX语句(x + y)上的表达式与查询中显示的表达式(y + x)不同。这两个表达式可能在数学上是等价的,但SQLite查询规划器认为它们是相同的,而不仅仅是等价的。所以下面重写查询:
SELECT * FROM t2 WHERE x+y=22;
第二个查询可能会使用索引,因为现在WHERE子句(x + y)中的表达式与索引中的表达式完全匹配。
对CREATE INDEX语句中出现的表达式有一些合理的限制:
表达式只能在CREATE INDEX语句中使用,而不能在 CREATE TABLE语句中的UNIQUE或PRIMARY KEY约束中使用。
索引表达式的能力已添加到SQLite 版本3.9.0(2015-10-14)。早期版本的SQLite将无法使用在表达式上使用索引的数据库。