使用计数器

时间:2017-01-12 07:23:13

标签: mysql sql

我想要实现的目标:

我正在开发包含产品目录的网站 这是与我的问题相关的实体的规范化模型(简化):

enter image description here

因此存在一些产品特征(如本例中的大小和类型),它们都具有预定义的值集(例如,存在大小1,2和3,类型可以是1,2或3(这些集合没有)为了平等,只是例子。)) 产品与每个功能之间的关系是多对多的" - 一个特征的不同值不相互排斥 我的任务是构建表单,允许用户根据产品的功能过滤搜索结果。屏幕截图示例:

enter image description here

使用" 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中的第二个查询;剩余部分"部分)。

  • 替代架构:
    enter image description here

非规范化模型,其中每个要素的值是Products表中的布尔列 这里的查询很明显:

    select * from products
    where `size_1` = 1 and `size_2` = 1
      and `size_3` = 1 and `size_5` = 1;

在应用程序代码中保持奇怪且难以维护,但在~0.056COUNT秒完成。

这些方法本身都不是可接受的,因为它们会增加~30倍(填充表格中的所有计数器),从而提供不充分的响应时间。

  • 缓存和预计算
    数据库中的数据每天只会更新几次(例如,甚至可能是2),因此我可能会在数据更新时预先计算所有过滤器组合的计数(我还没有测到必要的时间)诚实),但无论如何也不会工作 - 搜索表单包含具有任意值的字段(如最小/最高价格和按产品名称搜索文本),我无法预先计算。< / p>

  • 动态加载计数器的形式 渲染表单,但通过AJAX获取数字,因此用户可以看到页面,然后,经过相当长的等待,数字。这是我最后的想法,但对我来说服务质量似乎很差(可能比没有柜台更差)。

我被困住了。任何提示?可能是我没有看到更大的图片?我很乐意接受任何建议。

UPDATE :如果我们忘记了计数器,那么只使用这样的过滤器(或者我做错了什么)检索结果的有效且常用的方法(查询)是什么?喜欢&#34;找到所有请求标签的帖子&#34;模型,这是等价的。我怀疑它可能比我的0.230秒(查询#2)更快,考虑到MySQL的小行数(?)。

1 个答案:

答案 0 :(得分:1)

你可以

  1. 创建一个将存储所有可能组合的表格(product_id&lt;&gt; size_id&lt;&gt; type_id)
  2. 当管理员从后端对产品进行任何更改时(假设将有后端管理),更新此表
  3. 在前端,对于过滤器,请使用此表而不是产品表,并在触发过滤查询后提取产品ID
  4. 获得结果的产品ID列表后,您可以使用这些产品ID获取实际数据
  5. 我之前使用过它,它对我有用,你可以先创建表并尝试运行查询来检查响应时间。

    希望这有帮助。