SQL 字符串字段与多个 int/varchar 字段的性能

SQL performance for string field vs multiple int/varchar fields

我正在努力使数据库设计正确,但我不确定应该选择 2 个选项中的哪一个。将有大约 20 个布尔值用于过滤(为简单起见,样本中有 4 个)。

选项 1)

每个道具都有一个 int(1) 或 varchar(1) 字段。查询的过滤器部分可能像

WHERE prop1=1 AND prop3=1 AND prop4=1

选项 2)

使用带有代表道具的字符的单个文本字段

然后类似于选项 1 的查询的过滤器部分将像

WHERE props LIKE '%a%' AND props LIKE '%c%' AND props LIKE '%d%'

或者如果字符是排序的:

WHERE props LIKE '%a%' AND props LIKE '%cd%'

我的想法是选项 2 使添加新道具更容易,所以我喜欢这个选项,但是 LIKE 比较器的性能会比相等比较器差吗?与多个 int(1) 或 varchar(1) 相比,使用单个文本有什么区别吗?我没有想到的任何其他好处或缺点?

从性能的角度来看,这两个选项都有缺点:

  1. 几乎不可能对 20 列进行正确的索引,无论它们的数据类型如何,因为查询可能因设置条件 prop1、prop1 + prop2、prop2 + prop3、prop2 + prop4 等而异。所以你需要很多复合索引。此外,由于基数较低(值只能为 0 或 1,请参阅 here for example),布尔值的索引通常表现不佳。

  2. 另一方面,带有前导 % 的 LIKE 语句也是一个性能问题。关闭 % 可以,但前导 % 被确定为很慢。

我在这里看到您想为您的记录分配一组属性,每条记录可以分配 0..n propX,并且您想有效地过滤它。就像一个用户可以分配 0,1,2,...n 个角色。在关系数据库中,它被归类为经典的多对多关系。如果您使用可能的 props 设置 table 并使用联接 table 将它们连接到您的记录,例如 detailed here,您可以仅使用索引数量有限。

主要问题是您是否可以 运行 比扫描整个 table 更快。答案是否定的,除非可以使用 Index(es) 单独处理少量布尔值。

您的 WHERE bools LIKE '%a%c%d%' 是将任意数量的标志组合在一起的巧妙技巧。不过需要逐行查看,LIKE略重

INT(1) 占用 4 个字节加上开销。 TINYINT就是你要钓的东西;它需要 1 个字节,加上开销。

具有最多 64 个布尔值的 SET 是另一种技术。编码有点笨拙,但效率很高

INT UNSIGNED(最多 32 个)或 BIGINT UNSIGNED(最多 64 个)标志的实现类似于 SET,并且最多占用 8 个字节。但是编码相当笨拙。让我们在最低有效位中从 0 开始对位进行编号。

WHERE (bools & ( (1 << 0) | (1 << 2) | (1 << 3) ) ) = 
               ( (1 << 0) | (1 << 2) | (1 << 3) )

将检查位 0、2 和 3 是否都已设置。 (这就像您对 a、c、d 的测试。)使用这种方法可以实现多种 AND 和 OR。 (您可以预先计算这些位值——在此示例中为 13。或者使用位文字:0b1101。)

SET 或 INT 中的位的好处是每行中的 'speed'。不过,必须测试所有行。

因此,我建议对布尔值等进行分类,并决定哪些需要索引以及哪些可以进入此组合列或非布尔型的组合 JSON 列。