【问题标题】:Inner join in mysql take a long timemysql内部连接需要很长时间
【发布时间】:2019-10-07 19:34:29
【问题描述】:

我有超过 1,000,000 的表联系人和其他大约 20,000 条记录的表城市。需要获取所有在联系人表中使用过的城市。 联系人表具有以下列 ID、姓名、电话、电子邮件、城市、州、国家、邮政、地址、经理_Id 城市表有 身份证号,城市

我为此使用了 Inner join,但它需要很长时间才能完成。查询执行时间超过 2 分钟。

我使用了这个查询

SELECT cities.* FROM cities 
INNER JOIN contacts ON contacts.City = cities.city
WHERE contacts.manager_Id= 1

也在 manager_Id 上创建了索引。但它仍然很慢。

【问题讨论】:

  • city 字段上的索引可能更有帮助,但实际上,contacts 应该引用 cities.id,而不是 cities.city;用于更快的整数比较。
  • 你有关于城市字段的索引吗?

标签: mysql sql


【解决方案1】:

为了获得更好的性能,您可以添加索引

上表城市栏city

在表上联系列上的复合索引(manager_id, city)

【讨论】:

  • @MarlinPierce 。可能是..答案更新了..谢谢
  • 谢谢,但问题是联系人表有近 20 列和 5 个单列已经建立索引,以及 2 个复合索引,是否更喜欢在表上使用多个索引
  • 您应该评估您真正需要提高性能的查询和最常用的查询,并根据这些评估应用索引.. .. 为了提高 sql 的性能,您需要索引.. 但您必须平衡索引数量尊重您的实际需求
  • @MarlinPierce,你能否解释一下,首先拥有 manager_id 应该如何更快?
  • @user3337590 .. 使用 manager_id 作为索引 ins 中的第一列与您在 where 子句中有文字值的事实有关 .. 在这种情况下,where 子句和索引内容之间的数学运算可以减少索引中扫描的行数并提高性能(希望我的评论很清楚)
【解决方案2】:

先过滤contacts再加入cities

SELECT ct.* 
FROM cities ct INNER JOIN (
  SELECT city FROM contacts
  WHERE manager_Id = 1
) cn ON cn.city = ct.city

您需要两个表中的citycontacts 中的manager_id 的索引。

【讨论】:

  • 您认为与其在 city 和 manager_Id 上在联系人表上设置 2 个不同的索引,不如在 (city, manager_Id) 上设置 1 个复合索引会更好吗?
  • 不,在这种情况下不是。
  • 能否解释一下原因?
  • 过滤联系人需要 manager_Id 的索引 (WHERE manager_Id = 1)。每个表中的其他 2 个索引用于连接 ON cn.city = ct.city。我认为这个查询不需要复合索引。
  • 感谢您的帮助,仅在联系人表上使用复合索引 (manager_id, city) 会快得多,但如果对单个列使用 2 个不同的索引,则速度不会快得多
【解决方案3】:

正如其他人所指出的那样,有适当的索引,我想进一步澄清一下。您正在专门寻找 MANAGER ID = 1 的联系人。预计不会是一个人,但可能是很多人。因此,将 MANAGER ID 放在首位将优化让我拥有该经理的所有人。通过 (manager_id, city) 将城市作为索引的一部分,您将需要优化的两个数据元素作为索引的一部分。这样引擎就不必去原始数据页面来获取感兴趣的其他部分。

现在,您需要所有的城市信息(因此连接到该 ID 上的城市表)。

由于您只查询 CITIES 而不是实际的联系人信息,因此您可能需要 DISTINCT City ID。假设一位经理负责 50 个人,其中大多数人住在同一个城市或邻近城市。您可能有 5 个不同的城市?这也会限制您的加入结果集。

话虽如此,我会做一个后续操作,对于 MySQL,使用 STRAIGHT_JOIN 可以通过“按照我写的方式进行查询,不要为我考虑”来帮助优化。

select STRAIGHT_JOIN
      cty.*
   from
      ( select distinct c.City
           from Contacts c
           where c.Manager_ID = 1 ) PQ
         JOIN Cities cty
            on PQ.City = Cty.City

“PQ”是一个别名,代表我对给定经理的 DISTINCT 城市的“预查询”。

同样,在 (manager_id, city) 上的联系人表上有一个索引。在 city 表上,我希望并索引 (city)。

【讨论】:

    【解决方案4】:

    您需要两个索引,每个表上一个。

    contacts 表上,第一个索引manager_Id,然后是City

    CREATE INDEX idx_contacts_mgr_city ON contacts(manager_Id, City);
    

    cities 表上,只需索引`City。

    【讨论】:

    • 谢谢,但问题是联系人表有近 20 列和 5 个单列已经建立索引,以及 2 个复合索引,是否更喜欢在表上使用多个索引
    • 对于这个查询,如果你在(manager_Id, City) 上有一个索引,这个查询将不会使用任何其他索引。 (不过,索引可能用于其他查询。)
    【解决方案5】:

    “联系人”表中的“城市”字段是 VARCHAR 吗?

    如果是这样的话,我在这里看到了很多东西。 首先,由于您已经在“城市”表中拥有相应城市的“ID”,我不明白为什么不使用“联系人”表中的“城市”表中的相同“ID” .

    您可以将“IdCity”字段添加到“联系人”表中,这样您就不必修改现有记录。 您必须为每条记录手动插入“IdCity”,或者您可以使用“cities”表创建查询,然后比较“idCity”,但在“联系人”中插入“城市”(城市名称) ' 表。

    返回您的查询: 然后,使用 INT JOIN 而不是 VARCHAR JOIN。由于您有很多记录,这可能会在性能上显示出重要的意义。

    【讨论】:

      【解决方案6】:

      您似乎需要添加两个索引,一个在cities.city 上,一个在(contacts.manager_Id, contacts.city) 上。这应该会大大加快速度。

      【讨论】:

      • 索引应基于合格组件。在这种情况下,与特定经理联系。这座城市只是一个结果集。
      • @DRapp 是的,你是对的。我已经更新了我的答案。也许我回答的时候有点太快了。再说一次,像这样的简单查询,即使有这些表行数,也不应该花费 120 秒。甚至没有 120 毫秒。
      猜你喜欢
      • 1970-01-01
      • 2013-12-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多