我想要实现的目标:
我正在开发包含产品目录的网站 这是与我的问题相关的实体的规范化模型(简化):
因此存在一些产品特征(如本例中的大小和类型),它们都具有预定义的值集(例如,存在大小1,2和3,类型可以是1,2或3(这些集合没有)为了平等,只是例子。)) 产品与每个功能之间的关系是多对多的" - 一个特征的不同值不相互排斥 我的任务是构建表单,允许用户根据产品的功能过滤搜索结果。屏幕截图示例:
使用" AND"混合一个要素的多个选中值。逻辑,所以如果我检查了尺寸一和三,我需要所有具有两种尺寸的产品(+可能有任何其他尺寸,这并不重要,但必须存在选定的尺寸)。
功能的每个值附近的数字表示产品数量,如果用户现在检查此值,则返回该数量。因此,它实际上是许多产品满足过滤器"当前有源滤波器+应用这一值"。
当用户检查/取消选中任何值时,必须考虑新的"当前过滤器"来更新计数器。
问题:
实际使用案例是:〜200k产品,~6个特征,每个〜5-15个值
我的COUNT
查询(特别是选定数量相当多的选项)速度太慢,并且为了渲染表单,我需要尽可能多的计数以及所有过滤器的值 - 总计会产生不可接受的响应时间。 / p>
我尝试了什么:
查询检索结果:
select * from products p, product_size ps
where p.id = ps.product_id
and (ps.size_id IN (1, 2, 3, 5))
group by p.id
having count(p.id) = 4;
(这是为了同时选择尺寸为1,2,3和5的产品)
它在~0.360
秒内完成120k产品,几乎同时以COUNT
缠绕它。此查询不允许多个功能(但我可以将所有功能的值放在一个表中)。
检索同一组的另一个查询:
SELECT ps1.product_id
FROM product_size AS ps1, (SELECT id FROM size AS s1 WHERE id IN (1, 2, 3, 5)) AS t
WHERE ps1.size_id = t.id
GROUP BY ps1.product_id
HAVING COUNT(ps1.size_id) = (SELECT COUNT(id) FROM (SELECT id FROM size AS s2 WHERE id IN (1, 2, 3, 5)) AS t2);
它在~0.230
秒内完成(同时包含在COUNT
中)并且也不允许多个功能。
这是我在此处找到的修改后的查询:https://www.simple-talk.com/sql/t-sql-programming/divided-we-stand-the-sql-of-relational-division/(&#34中的第二个查询;剩余部分"部分)。
非规范化模型,其中每个要素的值是Products表中的布尔列 这里的查询很明显:
select * from products
where `size_1` = 1 and `size_2` = 1
and `size_3` = 1 and `size_5` = 1;
在应用程序代码中保持奇怪且难以维护,但在~0.056
时COUNT
秒完成。
这些方法本身都不是可接受的,因为它们会增加~30倍(填充表格中的所有计数器),从而提供不充分的响应时间。
缓存和预计算
数据库中的数据每天只会更新几次(例如,甚至可能是2),因此我可能会在数据更新时预先计算所有过滤器组合的计数(我还没有测到必要的时间)诚实),但无论如何也不会工作 - 搜索表单包含具有任意值的字段(如最小/最高价格和按产品名称搜索文本),我无法预先计算。< / p>
动态加载计数器的形式 渲染表单,但通过AJAX获取数字,因此用户可以看到页面,然后,经过相当长的等待,数字。这是我最后的想法,但对我来说服务质量似乎很差(可能比没有柜台更差)。
我被困住了。任何提示?可能是我没有看到更大的图片?我很乐意接受任何建议。
UPDATE :如果我们忘记了计数器,那么只使用这样的过滤器(或者我做错了什么)检索结果的有效且常用的方法(查询)是什么?喜欢&#34;找到所有请求标签的帖子&#34;模型,这是等价的。我怀疑它可能比我的0.230
秒(查询#2)更快,考虑到MySQL的小行数(?)。
答案 0 :(得分:1)
你可以
我之前使用过它,它对我有用,你可以先创建表并尝试运行查询来检查响应时间。
希望这有帮助。