多列

时间:2017-12-14 16:11:46

标签: sql firebird firebird2.5

这适用于Firebird 2.5。

我有一个表T,其索引由2列组成,比如ColA和ColB。如果我正在做: SELECT * FROM T WHERE ColA=...,所以WHERE子句只在A列上,Firebird会为列ColB设置默认值,还是索引的优点,还是不能在所有索引中使用?

一点背景: 我正在进行数据库升级。这就是我所拥有的:

CREATE TABLE user(
     newid BIGINT NOT NULL,
     oldid BIGINT NOT NULL,
     anotherCol INT);

CREATE INDEX idx ON  user(oldid, anotherCol);

CREATE TABLE order(
     RefUser BIGINT);

order.RefUser是oldid,我需要将它们更改为newid。我使用此查询执行此操作:

UPDATE order o SET o.refuser = (SELECT u.newid FROM user u WHERE u.oldId = o.refuser);

此时,oldid仍然是独一无二的,但后来只能保证(oldid,anotherCol)unicity,因此索引和newid的创建。

用户表是几百万条记录,订单表是几十万:这个查询需要一个多小时。我想看看如何改进它(不热衷于在这么长的时间内关闭关键服务)。

1 个答案:

答案 0 :(得分:4)

假设索引统计信息是最新的,或者至少对优化器来说足够好,那么Firebird可以(通常会)使用多列索引,而不是所有列都是where子句的一部分。唯一的限制是它只能用于第一列(或索引的前缀')。

所以用

CREATE INDEX idx ON  user(oldid, anotherCol);

Firebird可以使用idx索引where oldid = 'something',但不能where anotherCol = 'something'

不,Firebird不会"为列[anotherCol]" 设置默认值。它对索引执行范围扫描,并返回具有匹配oldid前缀的所有行。

从技术上讲,Firebird通过组合Firebird for the Database Expert: Episode 1 - Indexes中描述的列来创建索引键,这意味着索引中的值类似于:

0<oldid> 1<anotherCol> : row_id

例如(简化,如在现实生活中Firebird也进行前缀压缩)

0val1 1other1 : rowid1
0val1 1other2 : rowid4
0val1 1other3 : rowid6
0val2 1other1 : rowid2
...

使用where oldid = 'val1'时,Firebird会在索引中搜索以0val1 1开头的所有条目(就好像它在单个列上搜索0val1 1%一样)。在这种情况下,它将匹配rowid1,rowid4和rowid6。

虽然这很有效,但是如果只在oldid上进行大量查询,那么最好只在oldid上创建一个列索引,因为这个索引会更小,因此可以更快地遍历搜索记录时当然,缺点是更多的索引会对插入,更新和删除产生性能影响。

另见Concatenated Indexes上的Use The Index, Luke