【问题标题】:SQLite use autoindex instead my own indexSQLite 使用自动索引而不是我自己的索引
【发布时间】:2016-02-25 11:19:54
【问题描述】:

我对 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=?))

【问题讨论】:

  • “社交”中有多少行?
  • 嗨@MikeSherrill'CatRecall'。我已经编辑了我的问题。一旦你以前看过这个编辑版本,我就有两个表的问题。我觉得这个更适合我的问题。
  • 好的。 “用户”有多少行?
  • 一百万左右,但我没有遇到性能问题,但我只想知道为什么sqlite会这样做?我认为使用我自己的索引比使用它的索引更好。

标签: sql indexing sqlite pysqlite


【解决方案1】:

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

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

Source

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


要查看 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=?)

【讨论】:

  • ANALYZE 本身需要一些时间,因此请延长查询时间。在与数据库的每个连接中运行 ANALYZE 是否正确,或者对所有新连接只运行一次?
  • @ChristoforusSurjoputro:您只需要在数据库内容发生很大变化(我添加了一百万行)、架构更改或您只想确保统计信息更新时运行 ANALYZE -检查查询计划之前的日期。
【解决方案2】:

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

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

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

【讨论】:

  • 使用INDEX BY子句强制sqlite使用其他索引是对的,但不建议在生产中使用。
【解决方案3】:

在这里看到一些问题。

  1. 第一个 SQL 语句(CREATE TABLE ...)由于最后一列和右括号之间的额外逗号而格式错误。

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

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

  4. 最后,表名 social 没有在您提供的有限架构中定义,所以我们真的无法知道哪些真正的索引可用。

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

【讨论】:

    【解决方案4】:

    来自the documentation

    在多个索引之间进行选择

    (...)

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

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

    (...)

    因此,您可以运行 the analyze command 重新扫描索引,但这并不能保证优化器会更喜欢您的索引。

    要强制使用给定的索引,您可以使用INDEXED BY 短语。来自the documentation

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

    【讨论】:

    • ANALYZE 命令使查询在我的情况下需要更多时间。正如我在其他评论中所说,对于 INDEX BY,不建议在生产中使用。
    猜你喜欢
    • 2013-01-13
    • 2010-10-31
    • 1970-01-01
    • 1970-01-01
    • 2020-05-09
    • 2012-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多