如何解决字符串字段与多个 int/varchar 字段的 SQL 性能
我正在努力使数据库设计正确,但我不确定应该选择哪两个选项。将有大约 20 个布尔值用于过滤(为简单起见,示例中为 4 个)。
- prop1
- prop2
- prop3
- prop4
选项 1)
每个道具的 int(1) 或 varchar(1) 字段。查询的过滤器部分可能类似于
WHERE prop1=1 AND prop3=1 AND prop4=1
选项 2)
使用带有代表道具的字符的单个文本字段
- a:prop1
- b:prop2
- c:prop3
- d:prop4
那么类似于选项 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) 相比,使用单个文本有什么区别吗?我没有想到的任何其他好处或缺点?
解决方法
主要问题是你是否可以比扫描整个表运行得更快。答案是否定的,除非可以使用 Index(es) 单独处理少量布尔值。
您的 WHERE bools LIKE '%a%c%d%'
是将任意数量的标志进行 AND 运算的巧妙技巧。但是,它需要查看每一行,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 中的位的好处是每行中的“速度”。尽管如此,必须测试所有行。
因此,我建议对您的 bool 等进行分类,并决定哪些需要索引,哪些可以放入此组合列或非 bool 的组合 JSON 列中。
,从性能的角度来看,这两个选项都有缺点:
-
几乎不可能为 20 列建立正确的索引,无论它们的数据类型如何,因为查询可能因设置条件 prop1、prop1 + prop2、prop2 + prop3、prop2 + prop4 等而异。所以你需要很多复合索引。此外,布尔值的索引通常表现不佳,因为基数较低(值只能为 0 或 1,请参阅 here for example)。
-
另一方面,带有前导 % 的 LIKE 语句也是一个性能问题。关闭 % 可以工作,但确定领先 % 很慢。
我在这里看到的是,您希望为记录分配一组属性,每条记录可以分配 0..n 个 propX
,并且您希望对其进行有效过滤。就像用户可以分配 0,1,2,...n 个角色一样。在关系数据库中,它被归类为经典的多对多关系。如果您使用可能的 props
设置一个表,并使用连接表将它们连接到您的记录,例如 detailed here,您可以仅使用有限数量的索引进行良好的查询。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。