SQLite使用autoindex而不是我自己的索引

时间:2016-02-25 11:19:55

标签: sql indexing sqlite pysqlite

我在UNIQUE表中遇到了SQLite autoindex的问题。我创建了如下表格。

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使用自己提供的autoindex。如何避免这使用我自己的索引而不是它的自动索引? 我怎么试试:

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 个答案:

答案 0 :(得分:2)

在你的情况下,我认为" sqlite_autoindex_user_1"是SQLite用于在" email"上实现声明约束的索引。尽管有这个名字,但它是一个内部索引,而不是一个自动索引。

  

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

Source

查询优化器决定使用索引" email"会是最快的。这可能是正确的。

要了解SQLite如何使用覆盖索引" medp",请构建一个这样的测试表。

ID

如果您愿意,请插入一百万行。

public static Result SaveCutomer(Customer customer)
{
    using (AshdorEntities context = new AshdorEntities())
    {
        try
        {
            Contact con = null;
            if (customer.customerId == 0)//new customer
            {
                customer.enterDate = DateTime.Now;
                customer.Contact.dateEnter = customer.enterDate;
                con = context.Contact.Add(customer.Contact);
                customer.Contact = con;
                customer.customerId = con.contactId;

            }
            else
                context.Customer.Attach(customer);

            context.Entry(customer).State = con != null ?
                         EntityState.Added :
                         EntityState.Modified;
            context.SaveChanges();
        }
        catch 
        {
            return new Result() { status = false, massege = MassegesResult.ADDING_FAILED };
        }

        return new Result() { status = true, massege = MassegesResult.ADDING_SUCCESSFUL };
    }
}

答案 1 :(得分:2)

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

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

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

答案 2 :(得分:2)

这里看到一些问题。

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

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

  3. 使用我熟悉的任何语言都没有正确引用代表第三个SQL语句的字符串的引用。

  4. 最后,表名社交不是在您给出的有限模式中定义的,所以实际上我们无法知道可用的实际索引。

  5. 如果我们假设您的意思是"用户"当你键入" social",作为CL。说," autoindex"在使用中保证电子邮件是唯一的,因此它不需要任何其他东西。如果您还不需要name列,它可能已使用您的显式索引作为覆盖索引,但由于您的显式索引不包含name列(根据select语句的要求),因此它认为自动索引最佳。此外,对于这种情况,自动索引几乎肯定更好,因为较小的索引(仅电子邮件与电子邮件和密码)意味着在尝试查找所请求的电子邮件地址时,可能会有更少的btree页面读取。换句话说,电子邮件地址的索引只是比电子邮件和密码索引小的索引。

答案 3 :(得分:1)

来自the documentation

  

在多个指数之间进行选择

     

(...)

     

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

     

帮助优化程序更准确地估算工作量   参与使用各种索引,用户可以选择运行   ANALYZE命令。 ANALYZE命令扫描数据库的所有索引   两个或多个指数和收集之间可能存在选择的地方   有关这些指数的选择性的统计数据。统计数据   通过此扫描收集的数据存储在特殊的数据库表中   显示名称都以“sqlite_stat”开头。这些表的内容   因为数据库在重要之后发生了变化,所以不会更新   改变重新运行ANALYZE可能是谨慎的。结果一个   ANALYZE命令仅适用于数据库连接   在ANALYZE命令完成后打开。

     

(...)

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

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

  

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