1

我对 UNIQUE 表中的 SQLite 自动索引有问题。我已经创建了如下表。

c.execute('''CREATE TABLE user(
    id INTEGER PRIMARY KEY,
    email TEXT NOT NULL UNIQUE,
    password TEXT NOT NULL,
    name TEXT NOT NULL,
    );'''
)
c.execute('CREATE INDEX USR on user(email, password);')

但是当我使用解释查询计划检查时,SQLite 使用自己提供的自动索引。如何避免这种情况使用我自己的索引而不是它的自动索引?我如何尝试:

c.execute('EXPLAIN QUERY PLAN SELECT id, name FROM social WHERE email = "a@a.com" AND password = 'password'')

结果是:

(0, 0, 0, 'SEARCH TABLE social USING INDEX sqlite_autoindex_user_1(email=?))
4

4 回答 4

3

在您的情况下,我认为“sqlite_autoindex_user_1”是 SQLite 用于实现对“电子邮件”声明的约束的索引。尽管有这个名字,它是一个内部索引,而不是一个自动索引。

不要将自动索引与有时为实现 PRIMARY KEY 约束或 UNIQUE 约束而创建的内部索引(名称如“sqlite_autoindex_table_N”)混淆。此处描述的自动索引仅在单个查询期间存在,从不持久化到磁盘,并且仅对单个数据库连接可见。内部索引是 PRIMARY KEY 和 UNIQUE 约束实现的一部分,是持久的并持久化到磁盘上,并且对所有数据库连接都是可见的。由于遗留原因,术语“自动索引”出现在内部索引的名称中,并不表示内部索引和自动索引相关。

资源

查询优化器决定在“电子邮件”上使用索引是最快的。大概是对的。


要查看 SQLite 如何使用您的覆盖索引“medp”,请构建一个像这样的测试表。

create table social_test (
  id integer primary key, 
  name text not null,    -- no UNIQUE constraint for testing
  tampil integer not null
);

create index medp on social (name, tampil);

如果需要,插入一百万行。

analyze social;
explain query plan select * from social where name = 'facebook' and tampil = 6;
0|0|0|SEARCH TABLE social USING COVERING INDEX medp (name=? AND tampil=?)
于 2016-02-25T12:12:57.013 回答
2

由于 UNIQUE 约束,数据库知道对email列的查找最多可以返回一行。这意味着只password需要检查一个值,这可以通过查看已知的表行来轻松完成。

两列索引比单列索引需要更多空间,因此从磁盘加载它会更慢。

要强制数据库使用您的索引,您可以使用INDEXED BY 子句,但这不会提高性能。

于 2016-02-25T13:02:42.237 回答
2

在这里看到一些问题。

  1. 由于最后一列和右括号之间有一个额外的逗号,第一个 SQL 语句 (CREATE TABLE ...) 格式不正确。

  2. 第三个 SQL 语句 (EXPLAIN QUERY PLAN SELECT ...) 在指定的电子邮件周围使用双引号。出于向后兼容性的原因,SQLite 将允许这样做,但不建议这样做。

  3. 表示第三条 SQL 语句的字符串的引用在我熟悉的任何语言中都没有正确引用。

  4. 最后,表名 social 未在您提供的有限模式中定义,因此我们实际上无法知道哪些真正的索引可用。

如果我们假设您在键入“social”时指的是“user”,则为 CL。说,使用中的“自动索引”可确保电子邮件是唯一的,因此不需要其他任何内容。如果您也不需要 name 列,它可能已将您的显式索引用作覆盖索引,但由于您的显式索引不包括 name 列(如 select 语句所要求的那样),它认为自动索引最好。此外,对于这种情况,自动索引几乎肯定会更好,因为较小的索引(仅电子邮件与电子邮件和密码)意味着在尝试查找请求的电子邮件地址时可能会减少对 btree 页面的读取。换句话说,仅电子邮件地址的索引将比电子邮件和密码的索引更小。

于 2016-02-28T06:11:50.473 回答
1

文档中

在多个索引之间进行选择

(...)

当面临两个或更多索引的选择时,SQLite 会尝试估计使用每个选项执行查询所需的总工作量。然后它选择给出最少估计工作的选项。

为了帮助优化器更准确地估计使用各种索引所涉及的工作,用户可以选择运行 ANALYZE 命令。ANALYZE 命令扫描数据库的所有索引,其中可能有两个或多个索引之间的选择,并收集有关这些索引的选择性的统计信息。此扫描收集的统计信息存储在特殊的数据库表中,名称显示名称均以“sqlite_stat”开头。这些表的内容不会随着数据库的更改而更新,因此在进行重大更改后,重新运行 ANALYZE 可能是明智的。ANALYZE 命令的结果仅可用于在 ANALYZE 命令完成后打开的数据库连接。

(...)

因此,您可以运行分析命令来重新扫描索引,但这并不能保证优化器会更喜欢您的索引。

要强制使用给定的索引,您可以使用该INDEXED BY短语。从文档中

INDEXED BY 短语强制 SQLite 查询计划器在 DELETE、SELECT 或 UPDATE 语句上使用特定的命名索引。INDEXED BY 短语是 SQLite 扩展,不能移植到其他 SQL 数据库引擎。

于 2016-02-25T12:05:29.670 回答