哪些列应编入索引?

时间:2013-07-28 17:40:28

标签: sql database sqlite indexing

我们假设我有一个名为“users”的表。创作代码:

CREATE TABLE IF NOT EXISTS users 
(id_user INTEGER PRIMARY KEY AUTOINCREMENT, 
 username VARCHAR(32) COLLATE NOCASE, 
 passwd_hash VARCHAR(255) NOT NULL DEFAULT '', 
 passwd_salt VARCHAR(255) NOT NULL DEFAULT '', 
 email_addr VARCHAR(255) NOT NULL DEFAULT '');


CREATE INDEX IF NOT EXISTS idx_id_user ON users (id_user ASC);
CREATE INDEX IF NOT EXISTS idx_username ON users (username ASC);

当玩家加入服务器时,它会检查玩家的用户名是否已注册:

SELECT id_user 
FROM users 
WHERE username = '%s' LIMIT 1

如果用户名已注册,则会要求玩家登录。在登录尝试时我有这个:

SELECT passwd_hash, passwd_salt 
FROM users 
WHERE id_user = %d

然后它显然会检查两个密码是否匹配。

所以我的问题是,passwd_hashpasswd_salt应该编入索引吗?

4 个答案:

答案 0 :(得分:4)

执行查询时:

SELECT passwd_hash, passwd_salt
FROM users
WHERE id_user = %d;

SQL引擎将使用索引来查找正确的记录。然后它进入表本身以检索select子句所需的数据。

如果您将索引构建为:

CREATE INDEX IF NOT EXISTS idx_id_user ON users (id_user ASC, paswd_hash, passwd_salt);

然后SQL引擎只需使用索引即可满足查询。这可以提高性能。收益很小。

这是一般原则,但也有例外。某些数据库支持数据列上的聚簇索引的概念。在这样的索引中,表中的数据必须按键排序,表本身作为索引操作。但是,这不是SQLite索引选项。

答案 1 :(得分:4)

我会创建一个三列索引:(userid,password_hash,password_salt)。这可以用作覆盖索引以提高效率。

似乎这只是SQLite的一个小改进,但这个概念在其他可以缓存RAM中的索引的RDBMS实现中得到了更大的好处。

http://www.sqlite.org/queryplanner.html说:

  

1.7覆盖指数
  通过使用两列索引,“加州橘子的价格”查询更有效率。但SQLite可以通过三列索引做得更好,该索引还包括“价格”列:

     

此新索引包含查询使用的原始FruitsForSale表的所有列 - 搜索项和输出。我们称之为“覆盖指数”。因为所需的所有信息都在覆盖索引中,所以SQLite永远不需要查阅原始表来查找价格。

     

因此,通过在索引的末尾添加额外的“输出”列,可以避免必须引用原始表,从而将查询的二进制搜索的数量减少一半。这是性能的恒定因素改进(大约是速度的两倍)。但另一方面,它也只是一种改进;两倍的性能提升并不像表格首次编入索引时增加一百万倍那样引人注目。对于大多数查询,不太可能注意到1微秒和2微秒之间的差异。

您可能有兴趣阅读我的演示文稿How to Design Indexes, Really。我为MySQL用户做了那个演示,但这些概念也与SQLite和大多数其他RDBMS相关。

答案 2 :(得分:1)

没有。您只需索引要查询的列。

一旦找到记录,索引就无法更快地检索该记录中的其他列。

答案 3 :(得分:0)

我相信不。您在id_user上创建了一个索引,足以有效地获取密码信息。当然,我们不会因为检索它而在每个字段上创建索引。