You need to enable JavaScript to run this app. MySQL基于单字段多分组生成跨组选项全组合的高效实现咨询
优惠活动
大模型
产品
解决方案
定价
更多

MySQL基于单字段多分组生成跨组选项全组合的高效实现咨询

MySQL层面实现动态跨分组选项笛卡尔积的高效方案

方案适配性说明

  • 直接适配现有业务表结构,不需要修改任何字段
  • 自动兼容动态业务场景:单个产品的分组数量、每个分组下的选项数量变化时,不用手动调整计算逻辑
  • 相比原来PHP层逐次查询、逐组数组组装的实现,整体数据库查询次数从“产品总数+所有产品的分组数总和”收敛为单轮库内计算,内存占用大幅下降

核心实现逻辑(基于MySQL8.0+)

利用递归CTE自动逐层跨组拼接笛卡尔积,中间结果用JSON类型存储,最终拆解为对应分组的独立列输出,完整SQL如下:

-- 1. 预处理:固定产品下的分组排序、分组内选项排序
WITH group_rank AS (
    SELECT 
        Id_Product,
        `Group`,
        DENSE_RANK() OVER (PARTITION BY Id_Product ORDER BY `Group`) AS group_seq
    FROM product_option_config
    WHERE Id_Product = 1 -- 替换为待计算的产品ID
    GROUP BY Id_Product, `Group`
),
option_ranked AS (
    SELECT 
        poc.Id_Product,
        gr.group_seq,
        poc.`Group`,
        poc.Id_Option,
        poc.Name,
        ROW_NUMBER() OVER (PARTITION BY poc.Id_Product, poc.`Group` ORDER BY poc.Id_Option) AS option_seq
    FROM product_option_config poc
    INNER JOIN group_rank gr 
        ON poc.Id_Product = gr.Id_Product AND poc.`Group` = gr.`Group`
),
-- 2. 递归逐层拼接笛卡尔积
combos AS (
    -- 递归锚点:加载第一个分组的所有选项作为初始组合
    SELECT 
        Id_Product,
        group_seq AS max_group_seq,
        CAST(
            JSON_OBJECT(
                CONCAT('g', group_seq), 
                JSON_OBJECT('opt_id', Id_Option, 'opt_name', Name)
            ) AS JSON
        ) AS combo_data
    FROM option_ranked
    WHERE group_seq = 1

    UNION ALL

    -- 递归部分:将已有组合与下一分组的所有选项交叉拼接
    SELECT 
        or2.Id_Product,
        or2.group_seq AS max_group_seq,
        JSON_MERGE_PATCH(
            c.combo_data,
            CAST(
                JSON_OBJECT(
                    CONCAT('g', or2.group_seq), 
                    JSON_OBJECT('opt_id', or2.Id_Option, 'opt_name', or2.Name)
                ) AS JSON
            )
        ) AS combo_data
    FROM combos c
    INNER JOIN option_ranked or2 
        ON c.Id_Product = or2.Id_Product 
        AND or2.group_seq = c.max_group_seq + 1
    WHERE c.max_group_seq < (SELECT MAX(group_seq) FROM group_rank WHERE Id_Product = c.Id_Product)
)
-- 3. 最终输出:拆解JSON为对应分组的独立选项列
SELECT 
    Id_Product,
    JSON_EXTRACT(combo_data, '$.g1.opt_id') AS qty_opt_id,
    JSON_UNQUOTE(JSON_EXTRACT(combo_data, '$.g1.opt_name')) AS qty_opt_name,
    JSON_EXTRACT(combo_data, '$.g2.opt_id') AS size_opt_id,
    JSON_UNQUOTE(JSON_EXTRACT(combo_data, '$.g2.opt_name')) AS size_opt_name,
    JSON_EXTRACT(combo_data, '$.g3.opt_id') AS weigth_opt_id,
    JSON_UNQUOTE(JSON_EXTRACT(combo_data, '$.g3.opt_name')) AS weigth_opt_name
FROM combos
WHERE max_group_seq = (SELECT MAX(group_seq) FROM group_rank WHERE Id_Product = combos.Id_Product);

性能优化说明

  • 给(Id_Product, Group, Id_Option)建联合索引,10万级数据量下,单产品的全组合计算耗时可控制在百毫秒内
  • 计算前增加结果量校验:单产品所有分组的选项数乘积超过阈值(如10000)时直接跳过,避免生成超大结果集拖垮数据库
  • 针对MySQL5.7及以下不支持递归CTE的版本,可在PHP层先查询单个产品的所有去重分组,动态生成多表内连接SQL(即每个分组对应一张子查询表,通过Id_Product关联做内连接),这种动态JOIN的笛卡尔积计算效率远高于PHP层遍历数组组装
  • 原PHP方案可同步优化:去掉逐产品、逐分组的多次查询,改为一次性拉取所有待计算产品的全部选项行,在PHP内存中完成组装,用关联数组做索引减少重复数据加载,进一步降低内存占用

内容的提问来源于stack exchange,提问作者Nicolas Pellerin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.24 16:06:03