
通过一条带 IN 条件的 SELECT 查询一次性获取所有菜单类型数据,并在 PHP 层按 type 动态分组,可将 4 次数据库查询合并为 1 次,显著提升页面加载性能。
通过一条带 in 条件的 select 查询一次性获取所有菜单类型数据,并在 php 层按 type 动态分组,可将 4 次数据库查询合并为 1 次,显著提升页面加载性能。
在 CodeIgniter 3 项目中,频繁执行结构相似的 SQL 查询(如按不同 type 值筛选同一张表)是典型的性能瓶颈。您当前的代码分别对 starter、main_course、deserts 和 drinks 执行了 4 次独立查询,不仅增加了数据库连接与解析开销,还导致网络往返延迟叠加。优化的核心思路是:一次查全量,内存中再分类。
以下是推荐的重构方案:
✅ 推荐写法(单查询 + 动态键名映射)
// 在控制器中,替换全部 4 条查询为以下代码:
$getMenus = $this->db->query(
"SELECT * FROM table_name
WHERE status = '1'
AND type IN ('starter', 'main_course', 'deserts', 'drinks')
ORDER BY id DESC"
);
$allMenus = $getMenus->result_array();
// 初始化空数组,避免未定义索引警告
$data = [
'all_starter_menu' => [],
'all_maincourse_menu' => [],
'all_deserts_menu' => [],
'all_drinks_menu' => []
];
// 按 type 字段值动态归类到对应键下
foreach ($allMenus as $menu) {
$key = 'all_' . str_replace('_', '', $menu['type']) . '_menu';
// 兼容旧视图变量名(注意:main_course → maincourse,无下划线)
$data[$key][] = $menu;
}? 关键说明:
str_replace('_', '', $menu['type'])将main_course转为maincourse,确保生成的键名(如'all_maincourse_menu')与您原有视图中foreach ($all_maincourse_menu as ...)的变量名完全一致,无需修改任何 View 代码。
⚠️ 注意事项
-
字段一致性:确保
table_name中type字段值严格等于'starter'/'main_course'/'deserts'/'drinks'(大小写敏感),否则分类会遗漏。 -
索引优化:为提升查询效率,建议在数据库中为
(status, type, id)创建联合索引:ALTER TABLE table_name ADD INDEX idx_status_type_id (status, type, id);
-
扩展性考虑:若未来新增菜单类型(如
'appetizer'),只需在IN子句中添加,并在$data初始化数组中补充对应键名即可,逻辑清晰易维护。 -
安全性提醒:本例中
type值为固定枚举,不来自用户输入,因此直接拼接 SQL 是安全的;若需动态传入类型列表,请改用 CI 的 Query Builder 防注入(如$this->db->where_in('type', $types))。
✅ 视图层保持不变
您的 View 代码无需任何修改,仍可继续使用:
<!-- starter -->
<?php foreach ($all_starter_menu as $menu): ?>
<div class="col-md-6">
<h3><?= esc($menu['name']) ?></h3>
<strong><?= esc($menu['price']) ?></strong>
</div>
<?php endforeach; ?>
<!-- main course -->
<?php foreach ($all_maincourse_menu as $menu): ?>
<!-- 同上 -->
<?php endforeach; ?>(建议在输出时使用 esc() 防 XSS,增强安全性)
该方案将数据库查询次数从 4 次降至 1 次,配合合理索引,通常可降低 60%–80% 的页面首屏加载时间,同时保持代码可读性与向后兼容性。


















