优化SQL查询

时间:2013-10-22 18:04:02

标签: php mysql codeigniter optimization

我正在开发一个内容管理系统,我想听听你对以下内容的看法:

我有一张桌子page。我们假设它看起来像这样

ID | Title | Content
1  | Test  | This is a test

除此之外,我有一个page_option表(所以我可以存储与页面相关的选项,但我不希望有一个有限的选项列表 - 模块可以添加自己的选项到一个页面,如果需要。)

page_option表可能如下所示:

page_id | option_key  | option_value
1       | background  | red
1       | module1_key | chicken

现在要检索页面对象,我使用Active Record类执行以下操作(这是针对此问题的伪编码):

function get_by_id($page_id) {

 $this->db->where('id', $page_id);
 $page_object = $this->db->get('page');

 if($page_object->num_rows() > 0) {

   $page = $page_object->row();
   $this->db->where('page_id', $page_id);
   $options_object = $this->db->get('option');

   if($options_object->num_rows() > 0) {
     $page->options = $options_object->result();
   }

   return $page;

 }

 return $page_object->row();

}

我想知道的是,有没有办法在一个查询中执行此操作,以便选项键成为我的选择中的虚拟列,所以我得到:

ID | Title | Content        | background | module1_key
1  | Test  | This is a test | red        | chicken

在我的结果中,而不是对每一行进行单独的查询。如果有10,000个怎么办?等

非常感谢提前!

3 个答案:

答案 0 :(得分:1)

使用EAV(Entity-Attribute-Value)模型,您将始终不得不应对这些问题。由于查询的复杂性,它们的效率也不高(大多数都需要旋转)。

SELECT page_id,
  MAX(CASE WHEN option_key = 'background' THEN option_value END) background,
  MAX(CASE WHEN option_key = 'module1_key' THEN option_value END) module1_key,
  MAX(CASE WHEN option_key = 'module2_key' THEN option_value END) module2_key
FROM page_option
GROUP BY page_id

例如,给定此表:

| PAGE_ID |  OPTION_KEY | OPTION_VALUE |
|---------|-------------|--------------|
|       1 |  background |          red |
|       1 | module1_key |      chicken |
|       2 | module1_key |         duck |
|       3 | module1_key |          cow |
|       4 |  background |         blue |
|       4 | module2_key |        alien |
|       4 | module1_key |      chicken |

您将获得以下输出:

| PAGE_ID | BACKGROUND | MODULE1_KEY | MODULE2_KEY |
|---------|------------|-------------|-------------|
|       1 |        red |     chicken |      (null) |
|       2 |     (null) |        duck |      (null) |
|       3 |     (null) |         cow |      (null) |
|       4 |       blue |     chicken |       alien |

小提琴here

然后加入page表就是这样:)我省略了那个部分,以便将查询集中在分组本身。

答案 1 :(得分:0)

如果您可以使用activerecord类添加虚拟字段,则可以执行类似的操作:

 $this->db->add_field("(select group_concat(concat(option_key,':',option_value)  SEPARATOR ' ') from page_option where page_id=$page_id group by page_id)");

它不会是最佳的......

答案 2 :(得分:0)

如果option_keypage_idbackground(您没有两个或更多page_id==1 SELECT page.page_id, page.title, page.content, GROUP_CONCAT(option_key SEPARATOR '@') AS option_keys, GROUP_CONCAT(option_value SEPARATOR '@') as option_values, FROM page LEFT JOIN page_option ON page_option.page_id=page.page_id WHERE page.page_id=USER_SPECIFIED_ID ),您可以这样做:

$result

您可以执行此SQL查询并将其结果放入$result。应该完成$result[$i]["options"] = array_combine( explode("@",$result[$i]["option_keys"]), explode("@",$result[$i]["option_values"]) ); 的每个项目后

foreach

您可以使用array_walk执行此操作,也可以使用$result[$i]["options"]

在这些之后你有一个关联数组,其中包含{ "background" => "red", "module_key1"=> "chicken" } 中的选项:

{{1}}

我希望这是你想要的。