我正在构建一个具有网络支持的flutter应用程序,并使用drift作为本地存储数据库。我有一个具有以下架构的表:
CREATE TABLE Tasks(
Id INT NOT NULL PRIMARY KEY AUTOINCREMENT,
Name TEXT NOT NULL,
Priority INT NOT NULL
IsSynced BOOLEAN DEFAULT false);
是否可以进行不同的漂移异步数据库调用来获取具有不同优先级的未同步记录,或者我应该编写一个漂移查询来获取所有非同步记录并根据代码中的优先级将它们分开。我知道在这种情况下这并没有多大不同。由于漂移用于本地存储。我应该关心数据库调用的数量吗?
第一
Id INT NOT NULL PRIMARY KEY AUTOINCREMENT,
将导致错误,因为仅当列类型专门为 INTEGER 时才允许使用
AUTOINCREMENT
。你会失败,因为 AUTOINCREMENT is only allowed on an INTEGER PRIMARY KEY
第二个
如果您正在考虑效率,请考虑您是否真的需要
AUTOINCREMENT
。
AUTOINCREMENT
令人困惑的是,实际上并不会导致生成唯一的ID,而是一个约束(规则),它强加了这样的条件:如果生成该值,则该值必须大于任何已存在的值(如果不存在) .
约束/规则由附加表 sqlite_sequence 提供,每个表一行,保存有史以来分配的最高 id 值。
请参阅 https://www.sqlite.org/autoinc.html 以获取更全面的概述,其中还提到了 rowid,如果使用 INTEGER PRIMARY KEY,则由具有该定义的列作为别名。
注意第一句话。
我应该关心数据库调用的数量吗?
关于db调用次数,取决于使用场景。单个调用在不拆分的情况下会返回大量数据吗?如果是这样,单个块中的所有数据的处理效率可能会较低,与服务器通信可能成为瓶颈的多个调用相比。
您应该根据您的需求进行研究。
演示
AUTOINCREMENT
v just INTEGER PRIMARY KEY
(以及列类型灵活性)
也许考虑以下代码(在 SQLite 工具中使用(在本例中为 Navicat for SQLite)):-
/* Just in case the environment is dirty */
DROP TABLE IF EXISTS Tasks;
DROP TABLE IF EXISTS Tasks2;
/* Create the question's table (corrected by changing INT to INTEGER) */
CREATE TABLE IF NOT EXISTS Tasks(id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, priority int NOT NULL, issynced boolean_or_whatever_due_to_column_type_flexibility DEFAULT false);
/* The comparison */
/* NOTE without AUTOINCREMENT */
/* NOTE demonstration of flexible column types
i.e. a column type of the ridiculous "boolean_or_whatever_due_to_column_type_flexibility" column type
will be given a type affinity of NUMERIC due to BOOL (see 3.1.1 of https://sqlite.org/datatype3.html)
*/
CREATE TABLE IF NOT EXISTS Tasks2(id INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL, priority int NOT NULL, issynced boolean_or_whatever_due_to_column_type_flexibility DEFAULT false);
/* Insert base starting row for both tables */
INSERT INTO tasks VALUES(1000,'namexxx',99,1);
INSERT INTO tasks2 SELECT * FROM tasks;
/* insert another 1000 rows into tasks table */
WITH
/* create CTE (Common Table Expression (a temporary table that exists for the duration of the execution))
with 1 column, named i, that has a value 1, 2 3 ... to 1000 */
cte_generate_many(i) AS (
SELECT 1 /* first row */
UNION ALL
SELECT
i+1 /* 1 greater than the current row from the cte, so ever increasing */
FROM cte_generate_many
LIMIT 1000 /* recursively add rows till stopped (LIMIT 1000) */
)
INSERT INTO tasks (name,priority,issynced)
SELECT
'name'||i, /* Name will be "name?" where ? is 1 then 2 then 3 .... */
abs(random() % 10) + 1, /* priroity will be random between 1 and 10 */
(i % 3) > 0
FROM cte_generate_many
;
/* insert another 1000 rows into tasks2 table (comparison) same as previous bar into tasks2 not tasks table */
WITH
cte_generate_many(i) AS (
SELECT 1
UNION ALL SELECT i+1 FROM cte_generate_many LIMIT 1000
)
INSERT INTO tasks2 (name,priority,issynced)
SELECT 'name'||i,
abs(random() % 10) + 1,
(i % 3) > 0
FROM cte_generate_many
;
/* show the 2 tables and then sqlite sequence */
SELECT * FROM tasks;
SELECT * FROM tasks2;
SELECT * FROM sqlite_sequence;
/* demonstrate that AUTOINCREMENT constrain is not applied if value is given (not generated) */
INSERT INTO tasks VALUES(-1000,'namezzzz',99,1);
INSERT INTO tasks2 VALUES(-1000,'namezzzz',99,1);
SELECT * FROM tasks WHERE id < 1 UNION ALL SELECT * FROM tasks2 WHERE id < 1;
/* Cleanup */
DROP TABLE IF EXISTS Tasks;
DROP TABLE IF EXISTS Tasks2;
以上结果有4个结果。他们是:-
结果1
至:-
结果 2(即非常相同的表,但 没有
AUTOINCREMENT
)
还有可笑的列类型,它演示了 SQLite 列类型的灵活性(除非使用 STRICT),请参阅 https://sqlite.org/datatype3.html
至:-
结果3
结果4
1对2的讨论
简而言之,除了基于随机值的优先级之外,没有任何区别。因此,就 1000 行而言,自动增量与否没有什么区别。
可以看到,荒谬的列名没有真正的区别(事实上,BOOLEAN 本身不是实际的列亲和类型之一,它们是 NULL、INTEGER、REAL、TEXT、BLOB 和 NUMERIC)。然而,除了 rowid 或其别名(该 id 在任务和任务2中都存在),那么列可以保存任何类型的值,这是大多数其他 RDB 不提供的功能。
当谈到 AUTOINCRMENT 时,选择这个关键字是为了让 SQLite 与其他 RDB 更加兼容。