我有一个下面显示的表结构包含我所采用的角色结构:
让它成为“角色”表包含一些与用户角色相关的记录。现在我在这里使用了一列“is_archived(int)”,我用它来了解该角色是否仍然存在或删除。
所以我正在考虑该列的两个值:
对于我的表,最大记录将包含此列的“NULL”值,而默认值也为“NULL”。
现在我陷入困境,在这种情况下存在性能问题,因为我使用的是“NULL”而不是“0”。
我需要知道这种情况的优缺点(如“搜索性能”,“存储”,“索引”等)。
如果有利弊,最好的选择是什么?
我同意@RickJames关于NULL。不要在你想要使用像true
这样的实际值的地方使用NULL。同样,不要使用像0或''
这样的实际值来表示缺少值。
至于性能影响,您应该知道要搜索NULL的存在/不存在,您将使用谓词is_archive IS [NOT] NULL
。
如果对查询使用EXPLAIN,您将看到该谓词计为“范围”访问类型。而搜索单个特定值,例如, is_archive = 1
或is_archive = 0
是一种“ref”访问类型。
这将对某些查询产生性能影响。例如,如果您有(is_archived,created_on)索引,并且您尝试执行以下查询:
SELECT ... FROM roles
WHERE is_archived IS NULL AND created_on = '2017-01-31'
那么索引只有一半有用。 WHERE子句无法搜索索引中的第二列。
但是如果你使用实际值,那么查询就像:
SELECT ... FROM roles
WHERE is_archived = 0 AND created_on = '2017-01-31'
将在索引中使用这两列。
关于NULL存储的评论:
是的,在InnoDB存储引擎中,每行内部存储一个每列1位的位域,其中位指示每列是否为NULL。这些位紧凑地存储,即一个字节包含多达8位。位域之后是一系列列值。 NULL列不存储任何值。所以是的,从技术上讲,使用NULL可以减少存储空间。
但是,我建议你简化数据管理,并在false
时使用false
。不要对其中一个值使用NULL。我想如果你按照每行节省一个字节的规模来管理数据是个例外。例如,如果您正在管理数百亿行。
但是,在比这更小的范围内,潜在的空间节省不值得您添加到项目中的额外复杂性。
换句话说,InnoDB页面只填充每个数据页15/16。因此,InnoDB页面格式的开销可能大于从微优化布尔存储中获得的节省。
我的观点是NULL
用于“带外”,而不是用于克服带内值。如果存在任何性能或空间差异,则无关紧要。
对于true / false,请使用TINYINT NOT NULL
。它只有1个字节。你可以使用ENUM('false', 'true')
;它也是1个字节。
INT
,无论后面的数字,都需要4个字节。不要将INT
用于这种低基数的东西。
将NULL
表示“尚未知晓”或任何其他您不能说“真实”或“错误”的情况。 (因为你可能总是知道它是否'存档',NULL
在这里没有位置。
你甚至可以使用ENUM('male', 'female', 'decline_to_state', 'transgender', 'gay', 'lesbian', 'identifies_as_male', 'North_Carolina_resident', 'other')
。 (警告:这只是一个部分列表;最好设置一个表格和JOIN
。)