使用 JOIN'ed 映射表比同一张表中的多个字段更好?

Posted

技术标签:

【中文标题】使用 JOIN\'ed 映射表比同一张表中的多个字段更好?【英文标题】:Using JOIN'ed mapping tables better than multiple fields in the same table?使用 JOIN'ed 映射表比同一张表中的多个字段更好? 【发布时间】:2011-06-23 22:50:39 【问题描述】:

我有一个包含大约 360,000 条记录的表,这里对两个索引字段执行查询:

SELECT COUNT(*)
FROM emails
WHERE
department_id IN(1,2,3,4)
AND category_id IN (5,6,7,8)

(Time: 0.9624802)

           id: 1
  select_type: SIMPLE
        table: emails
         type: range
possible_keys: emails_department_id_idx,emails_category_id_idx
          key: emails_category_id_idx
      key_len: 5
          ref: NULL
         rows: 54018
        Extra: Using where

所以那里只使用了一个索引。 (当使用更简单的比较或范围标准时,我可以让索引合并工作,但我需要对 ID 列表进行这样的检查)。

在这里,我创建了两个新表来映射这种关系,并使用 JOIN 复制了相同的结果:

SELECT COUNT(*)
FROM emails
LEFT JOIN email_to_department ON (email_to_department.email_id = emails.id AND email_to_department.department_id IN (1,2,3,4))
LEFT JOIN email_to_category ON (email_to_category.email_id = emails.id AND email_to_category.category_id IN (5,6,7,8))
WHERE
email_to_department.department_id IS NOT NULL
AND email_to_category.category_id IS NOT NULL

(Time: 0.5217777)

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: email_to_category
         type: range
possible_keys: PRIMARY,category_id
          key: category_id
      key_len: 4
      ref: NULL
     rows: 61282
    Extra: Using where; Using index
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: email_to_department
         type: ref
possible_keys: PRIMARY,department_id
          key: PRIMARY
      key_len: 4
          ref: testdb.email_to_category.email_id
         rows: 1
        Extra: Using where; Using index
*************************** 3. row ***************************
           id: 1
  select_type: SIMPLE
        table: emails
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: testdb.email_to_category.email_id
         rows: 1
        Extra: Using index
3 rows in set (0.38 sec)

所以现在每个查询都使用一个索引,并且减少了几乎一半的时间。这是糟糕的设计吗?我应该以同样的方式编写其余的这些关系吗?

如果我以相同的方式添加更多条件,则查询的 JOIN 版本似乎变得更快,而另一个则或多或少保持不变。

只对单个索引字段进行简单查询当然非常非常快:

SELECT COUNT(*)
FROM emails
WHERE department_id IN(1,2,3,4)

我是否可以使用另一种策略来加快这类查询的速度?还有其他属性需要过滤,并且需要以不同的组合进行过滤,因此创建多列索引并没有真正的帮助。

【问题讨论】:

在您的第一个查询中,您可能希望考虑在 department_id 和 category_id 上添加一个键,如下所示,INDEX(department_id, category_id)。这将有助于使用索引的第一个查询过滤结果。 【参考方案1】:

这确实是一个关于数据库规范化的问题。您可以在许多地方查找有关该主题的信息。

基本答案 由于这方面的文献很多,而且存在很多差异,我只想指出它归结为权衡;速度与存储要求,或易用性与数据复制。您可能想了解什么是标准化,以便了解您为什么愿意或不愿意这样做。

进一步阅读 这是一个深奥的话题,您可能想了解更多信息 - 关于这些问题有数百本书和数千篇学术论文。例如,看看这个关于设计数据库的先前 SO 问题: Database design: one huge table or separate tables?,或者这个:First-time database design: am I overengineering? 或 Database Normalization Basics About.com。

【讨论】:

【参考方案2】:

我也同意 Jaitsu 关于在两个字段上创建复合键的观点。通常,您应该始终将具有较高基数的列放在复合索引的最前面。这样您就可以拥有更具选择性的索引。

【讨论】:

以上是关于使用 JOIN'ed 映射表比同一张表中的多个字段更好?的主要内容,如果未能解决你的问题,请参考以下文章

Mysql如何将数据从一个字段复制到同一张表中的另一个字段

想写一个DB2触发器,几张表有关联,修改其中一张主表中的某一个字段,其他关联表中的该字段也跟着联动修改

SQL中,如何将三个表中同一字段中的内容汇总到一个字段中?

DB2中2张表中有同一个字段名 要同时查询出2个字段怎么解决

MySQL的分表与分区

mysql同一张表中两个字段 关联另一张表的相同字段 查询出两个值