我试图从SQLite中挤出每一点性能,我有一个问题,这似乎很奇怪,因为SQLite中的功能似乎毫无意义。
例如:
CREATE TABLE "A_TEST" ( "ID" INTEGER PRIMARY KEY , "X" TEXT NULL) WITHOUT ROWID
然后尝试插入一条记录:
Insert into A_TEST (X) VALUES('Test String')
你会得到一个错误“NOT NULL constraint failed”
这是否意味着,对于WithoutRowID
,我必须在插入时指定自己的主键值?
我认为WithoutRowID
毫无意义的原因是:
1.你必须指定你自己的主键值,这使得任何批量插入选择语句都是多余的,因为我必须在插入时在主键中指定我自己的值。
1.如果我不使用WithoutRowID,我实际上将有2个主键,因为SQLite管理自己的RowID以及我自己的主键值。在1.7GB的数据库上,使用WithoutRowID将文件中索引的大小减少到1.3GB,因此400MB的差异是相当大的节省。
请告诉我,我不必提供自己的主键ID,如果它是INTEGER
,它实际上会提供一个针对主键的唯一ID。
5条答案
按热度按时间pobjuy321#
我刚刚发现SQLite 4是可用的-它看起来(从最初的阅读网页),主键将确实是真实的主键没有ROWID!Whoop Whoop。http://sqlite.org/src4/doc/trunk/www/design.wiki
8fsztsew2#
SQLite中有三种表:
1.具有INTEGER PRIMARY KEY的rowid表(其中PK列是内部rowid的别名),它们存储为按声明的主键排序的B树;
1.和2.几乎是相同的,除了你不会自动递增1。
因此,如果你想有自动递增,只需删除WITHOUT ROWID(从case 1移动到case 2)。WITHOUT ROWID只是对第三种情况的改进,在第三种情况下,主键约束需要一个单独的索引。
jfewjypa3#
这是否意味着,对于WithoutRowID,我必须在插入时指定自己的主键值?
是的(虽然可能没有一些努力或限制如下),如果你尝试:
然后你得到的东西沿着线:-
所以你需要有一个
PRIMARY KEY
,而SQLite不会提供一个值,因为通过指定WITHOUT ROWID
,你已经告诉SQLite你不想要这个特性。将上述内容更改为:
但是,您需要指定值。
上面的方法对于关联表很有用,如果主索引是根据你将要引用的列,而不是根据rowid,这基本上是按照插入顺序的,那么它可能会更有效。当然,对于这样的表,在不知道列的值的情况下,您可能不会插入一行。
因此,
WITHOUT ROWID
表有其用途。如果你真的想,你可以很容易地引入一个自动递增的数字使用'触发器'伴随着一个表与一个单一的行/列,存储最后使用或下一个数字使用,但为什么你会放弃rowid的简单复制rowid的为你做什么反正。
另一种替代方法是使用CURRENT_TIMESTAMP作为默认值。但是,不能执行批量插入,因为插入之间的间隔会导致UNIQUE约束冲突。
如果我不使用WithoutRowID,我实际上将有2个主键,因为SQLite管理自己的RowID以及我自己的主键值。在1.7GB的数据库上,使用WithoutRowID将文件中索引的大小减少到1.3GB,因此400 MB的差异是相当大的节省。
请告诉我,我不必提供自己的主键ID,如果它是一个整数,它实际上会提供一个针对主键的唯一ID。
当然,你的 “我自己的主键值” 不是神奇地生成的,也就是说,你知道这个值(假设它不仅仅是rowid的副本),所以它会被用于主键。
有趣的是,使用:
显示使用
WITHOUT ROWID
为PRIMARY KEY
提供了更大的灵活性,因为它不像rowid那样仅限于INTEGER
,TEXT PRIMARY KEY.....
也不限于INTEGER
。即上述结果:
Android的另一个注意事项
WITHTOUT ROWID
是在3.8.2版本中引入的,某些设备可能没有安装该版本或更高版本,因此WITHOUT ROWID
甚至可能不是某些Android应用程序的选项。如果你真的想要的话,可以举个例子:-
这是一个管理你自己的psuedo_autoincrement的例子。这不是按照1递增,而是根据指定的量(本例中为10)递增。它不完整,因为它没有上限检查/处理。
下面是插入3行后的结果:
下面是随附的序列表(准备好下一个插入,即e _seq是31):
关键(双关语无意)是触发器:
还有那个**:
这是在Android上使用以下方法检查/使用的:
DBHelper.java
MainActivty.java:-
产出是:
insrf1ej4#
这是否意味着,对于WithoutRowID,我必须在插入时指定自己的主键值?
是的,但您可以在插入时自动使用子选择生成它:
对于空表,
IFNULL(MAX(id),0)) + 1
将返回1
,否则将比具有当前最高值的行多一个。对于质量插入,这不会保持不变,因为所有
IFNULL(MAX(id),0)) + 1
都是同时计算的,并且具有相同的值,从而导致唯一约束冲突。但是,您可以生成mass insert语句,以便第一个偏移量为+ 1
,第二个偏移量为+ 2
,依此类推:11dmarpk5#
不幸的是,它看起来有点像狗的晚餐:https://www.sqlite.org/rowidtable.html
我引用(如果你不想读整页):“需要为流通中的数千亿个SQLite数据库文件保持向后兼容性。在一个完美的世界里,不会有“rowid”这样的东西,所有的表都将遵循WITHOUT ROWID表实现的标准语义,只是没有额外的“WITHOUT ROWID”关键字。不幸的是,生活是混乱的。SQLite的设计师为目前的混乱局面表示诚挚的歉意。