【问题标题】:How to avoid filesort when using left join and order by使用左连接和排序时如何避免文件排序
【发布时间】:2023-03-30 00:47:01
【问题描述】:

我有 3 个表:accounts、contacts 和 accounts_contacts(一个映射表)。 我在每个表中都有大约 100 万条记录。此查询使用文件排序,运行时间超过一分钟:

explain SELECT contacts.salutation salutation, contacts.first_name first_name, contacts.last_name last_name, contacts.title title, jt0_accounts.id account_id, jt0_accounts.name account_name

FROM contacts

LEFT JOIN accounts_contacts jt1_accounts_contacts ON (contacts.id = jt1_accounts_contacts.contact_id AND jt1_accounts_contacts.deleted = 0)

LEFT JOIN accounts jt0_accounts ON (jt0_accounts.id = jt1_accounts_contacts.account_id AND jt0_accounts.deleted = 0)

ORDER BY jt0_accounts.name DESC;

这是解释输出:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1    SIMPLE contacts    ALL NULL    NULL    NULL    NULL    195634  Using temporary; Using filesort
1    SIMPLE jt1_accounts_contacts   ref idx_contid_del_accid    idx_contid_del_accid    113 sugar7.contacts.id,const    1   
1   SIMPLE  jt0_accounts    eq_ref  PRIMARY,idx_accounts_id_del,idx_accounts_date_entered,idx_accnt_assigned_del    PRIMARY 108 sugar7.jt1_accounts_contacts.account_id 1   

如您所见,联系人表正在使用联系人表上的文件排序。

我尝试通过在“ORDER BY”之前添加“WHERE jt0_accounts.name ''”来摆脱文件排序,因此它变为:

explain SELECT contacts.salutation salutation, contacts.first_name first_name, contacts.last_name last_name, contacts.title title, jt0_accounts.id account_id, jt0_accounts.name account_name

FROM contacts

LEFT JOIN accounts_contacts jt1_accounts_contacts ON (contacts.id = jt1_accounts_contacts.contact_id AND jt1_accounts_contacts.deleted = 0)

LEFT JOIN accounts jt0_accounts ON (jt0_accounts.id = jt1_accounts_contacts.account_id AND jt0_accounts.deleted = 0)

WHERE jt0_accounts.name <> ''
ORDER BY jt0_accounts.name DESC;

它确实摆脱了联系人表上的文件排序,但它现在使用映射表上的文件排序:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  jt1_accounts_contacts   ALL idx_account_contact,idx_contid_del_accid    NULL    NULL    NULL    34994   Using where; Using temporary; Using filesort
1   SIMPLE  jt0_accounts    eq_ref  PRIMARY,idx_accounts_id_del,idx_accounts_date_entered,idx_accnt_name_del,idx_accnt_assigned_del PRIMARY 108 sugar7.jt1_accounts_contacts.account_id 1   Using where
1   SIMPLE  contacts    eq_ref  PRIMARY,idx_contacts_id_del,idx_contacts_date_entered   PRIMARY 108 sugar7.jt1_accounts_contacts.contact_id 1   Using where

idx_account_contact 索引由 account_id 和 contacts_id 组成。我尝试将它们添加到 WHERE 子句中,但似乎没有任何区别。

任何建议将不胜感激。 谢谢。

【问题讨论】:

    标签: mysql join sql-order-by filesort


    【解决方案1】:

    对于您的特定查询,您可能无能为力。但是,如果您将查询更改为使用inner join,您可能会有机会:

    SELECT c.salutation, c.first_name, c.last_name, c.title,
           a.id as account_id, a.name as account_name
    FROM accounts a JOIN
         accounts_contacts ac
         ON a.id = ac.account_id AND a.deleted = 0
         contacts c JOIN
         ON c.id = ac.contact_id AND ac.deleted = 0     
    ORDER BY a.name DESC;
    

    然后,尝试以下索引:accounts(name, deleted, id)accounts_contacts(account_id, contact_id)concats(contact_id, deleted)

    【讨论】:

    • 除非我弄错了,否则我不认为使用内部联接对我有用。因为我想显示联系人表中的所有记录,即使它没有关联的帐户。
    • 内连接的性能很好。我可以在原始查询中将“LEFT”替换为“INNER”,并立即得到结果。但结果不会是我所期望的。
    猜你喜欢
    • 1970-01-01
    • 2010-11-29
    • 2019-11-20
    • 2013-02-20
    • 1970-01-01
    • 1970-01-01
    • 2021-11-11
    • 2019-06-13
    • 1970-01-01
    相关资源
    最近更新 更多