我在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=?))
答案 0 :(得分:2)
在你的情况下,我认为" sqlite_autoindex_user_1"是SQLite用于在" email"上实现声明约束的索引。尽管有这个名字,但它是一个内部索引,而不是一个自动索引。
不要将自动索引与内部索引混淆(拥有 有时创建的名称如" sqlite_autoindex_table_N") 实现PRIMARY KEY约束或UNIQUE约束。自动 此处描述的索引仅在单个查询的持续时间内存在, 永远不会持久化到磁盘,并且只对单个数据库可见 连接。内部索引是PRIMARY实现的一部分 KEY和UNIQUE约束是持久的并且持久化到磁盘, 并且对所有数据库连接都可见。术语"自动索引" 由于遗留原因,它出现在内部索引的名称中 不表示内部索引和自动索引是相关的。
查询优化器决定使用索引" 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)
这里看到一些问题。
由于最后一列和右括号之间有一个额外的逗号,第一个SQL语句(CREATE TABLE ...)格式不正确。
第三个SQL语句(EXPLAIN QUERY PLAN SELECT ...)在指定的电子邮件周围使用双引号。 SQLite会出于向后兼容的原因允许这样做,但不建议这样做。
使用我熟悉的任何语言都没有正确引用代表第三个SQL语句的字符串的引用。
最后,表名社交不是在您给出的有限模式中定义的,所以实际上我们无法知道可用的实际索引。
如果我们假设您的意思是"用户"当你键入" social",作为CL。说," autoindex"在使用中保证电子邮件是唯一的,因此它不需要任何其他东西。如果您还不需要name列,它可能已使用您的显式索引作为覆盖索引,但由于您的显式索引不包含name列(根据select语句的要求),因此它认为自动索引最佳。此外,对于这种情况,自动索引几乎肯定更好,因为较小的索引(仅电子邮件与电子邮件和密码)意味着在尝试查找所请求的电子邮件地址时,可能会有更少的btree页面读取。换句话说,电子邮件地址的索引只是比电子邮件和密码索引小的索引。
答案 3 :(得分:1)
在多个指数之间进行选择
(...)
当面临选择时 两个或多个索引,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数据库引擎。