我的列是日期时间converted_at
。
我打算经常拨打WHERE converted_at is not null
拨打电话。因此,我正在考虑使用布尔字段converted
。检查字段是not null
还是false
时,它们之间的显着性能差异是什么?
感谢。
答案 0 :(得分:5)
如果事情在一个字段中是可以回答的,那么你更愿意将同一个事物分成两个字段。这会创建更多的基础架构,在您的情况下是可以避免的。
至于问题的核心,我相信大多数数据库实现,包括MySQL,都会有一个内部标志,无论如何都是boolean来表示字段的可空性。
你应该相信这是为你做的。
至于性能,更大的问题应该是分析您在数据库上运行的典型查询以及创建适当索引和分析表的位置,以改进执行计划以及在查询期间使用哪些索引。这个问题会对绩效产生更大的影响。
答案 1 :(得分:2)
在查询效果方面,使用WHERE converted_at is not null
或WHERE converted = FALSE
可能会相同。
但是如果你有这个额外的位字段,用于存储converted_at
字段是否为空,那么每当添加新行时,你必须以某种方式保持完整性(通过触发器?)每次更新列时。所以,这是一种去标准化。并且还意味着更复杂的代码。此外,您将在表上至少再有一个索引(这意味着插入/更新/删除操作稍慢)。
因此,我认为添加这个位字段并不好。
如果您可以将相关列从NULL
更改为NOT NULL
(可能通过规范化表格),您可能会获得一些性能提升(以获得更多表格为代价)。< / p>
答案 2 :(得分:0)
我对自己的用法有相同的问题。因此,我决定进行测试。 因此,我创建了我想象的3种可能性所需的所有字段:
# option 1
ALTER TABLE mytable ADD deleted_at DATETIME NULL;
ALTER TABLE mytable ADD archived_at DATETIME NULL;
# option 2
ALTER TABLE mytable ADD deleted boolean NOT NULL DEFAULT 0;
ALTER TABLE mytable ADD archived boolean NOT NULL DEFAULT 0;
# option 3
ALTER TABLE mytable ADD invisibility TINYINT(1) UNSIGNED NOT NULL DEFAULT 0
COMMENT '4 values possible' ;
最后一个是一个位字段,其中1 =已归档,2 =已删除,3 =已删除+已归档
首先要区别的是,您必须为optioon 2和3创建索引。
CREATE INDEX mytable_deleted_IDX USING BTREE ON mytable (deleted) ;
CREATE INDEX mytable_archived_IDX USING BTREE ON mytable (archived) ;
CREATE INDEX mytable_invisibility_IDX USING BTREE ON mytable (invisibility) ;
然后我使用真实的SQL请求在主表的13k记录上尝试了所有选项,这是它的外观
SELECT *
FROM mytable
LEFT JOIN table1 ON mytable.id_qcm = table1.id_qcm
LEFT JOIN table2 ON table2.id_class = mytable.id_class
INNER JOIN user ON mytable.id_user = user.id_user
where mytable.id_user=1
and mytable.deleted_at is null and mytable.archived_at is null
# and deleted=0
# and invisibility=0
order BY id_mytable
另外使用上面注释的过滤器选项。
使用了mysql 5.7.21-1 debian9
我的结论:
“为空”解决方案(选项1)更快,或者至少具有相同的性能。
另外2个(“ deleted = 0”和“ invisibility = 0”)的平均速度似乎要慢一些。
但是nullable字段选项具有决定性的优点:无需创建索引,更易于更新,更易于查询。而且使用的存储空间更少
(实际上,附加插入和更新也应该更快,因为mysql不需要更新索引,但是您永远不会注意到这一点。)
因此,您应该使用可为空的数据时间字段选项。