You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CodeIgniter 按逗号分隔分类ID数组查询食品数据的去重与性能优化

适配逗号分隔category_id的无重复高性能查询实现

核心问题根源

原有循环遍历分类ID单独查库的实现存在两个明确缺陷:

  • 多次发起数据库请求,造成不必要的IO性能损耗
  • 每个分类独立返回结果块,同一食品匹配多个分类时会在不同结果块中重复出现,最终形成嵌套冗余数组

优化实现方案

将分散的FIND_IN_SET条件合并为单次查询的OR匹配逻辑,把多次数据库请求压缩为1次,从根源上避免结果重复。

完整可运行代码

if (count($categoryIds) > 0 && count($allergyIds) == 0 ) {
    // 提前对传入分类ID做整数转换,从根源防范SQL注入
    $safeCategoryIds = array_map('intval', $categoryIds);
    $matchConditions = [];
    foreach ($safeCategoryIds as $singleCatId) {
        $matchConditions[] = "FIND_IN_SET($singleCatId, food.category_id)";
    }
    // 用OR拼接所有匹配条件,外层加括号避免和后续AND条件逻辑冲突
    $combinedMatch = '(' . implode(' OR ', $matchConditions) . ')';

    return $this->db->select('food.food_id,food_name,food_image,food_thumbnail,description,food_variations.price as price,is_active')
        ->from('food')
        ->join('food_variations', 'food_variations.food_id = food.food_id')
        // 第三个参数传FALSE表示不自动给这个条件加引号转义,因为我们已经提前做了安全校验
        ->where($combinedMatch, NULL, FALSE)
        ->where('food.restaurant_id', $restaurantId)
        ->where('food.is_active', '1')
        ->where('food.is_deleted', '0')
        ->where('food.food_status','3')
        ->where('food_variations.food_variation_id = food.default_food_variation_id')
        ->get()
        ->result_array();
}

实现效果说明

  • 查询仅执行1次,相比原来循环N个分类就查N次的模式,性能随分类数量提升线性优化
  • 返回结果为扁平的一维食品条目数组,同一食品无论匹配多少个传入的分类ID,都只会返回一次,完全消除嵌套重复的问题
  • 逻辑和之前单值category_id时用where_in的查询逻辑完全对齐,不会出现条件优先级错位的问题

兜底注意事项

  • 如果数据存在异常(比如food_variations关联重复导致条目重复),可以在select字段后加DISTINCT做去重兜底,修改select部分为:$this->db->select('DISTINCT food.food_id,food_name,food_image,food_thumbnail,description,food_variations.price as price,is_active')
  • 必须保留对传入分类ID的整数转换步骤,绝对不能直接把未校验的输入拼进SQL语句,避免注入风险

内容的提问来源于stack exchange,提问作者Rishi Saravadaa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.23 14:36:01