ruby on rails - MySQL polymorphic join condition with OR not using index -
i have tables departments
, employees
, , emails
in mysql 5.6.17 (for rails app). each department has many employees, , both departments , employees have many emails. want sort departments
number of emails entire department , individual employees within department. attempt:
select departments.*, count(distinct employees.id) employees_count, count(distinct emails.id) emails_count departments left outer join employees on employees.department_id = departments.id , employees.is_employed = true left outer join emails on (emails.emailable_id = departments.id , emails.emailable_type = 'department') or (emails.emailable_id = employees.id , emails.emailable_type = 'employee') group departments.id order emails_count desc limit 20;
unfortunately, query takes on 3 minutes complete. since query used in web interface, that's not workable timeframe. explain
gives:
+----+-------------+-------------+-------+-------------------------------------------------+----------------------------------+---------+-------------------------------+-------+------------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | | +----+-------------+-------------+-------+-------------------------------------------------+----------------------------------+---------+-------------------------------+-------+------------------------------------------------+ | 1 | simple | departments | index | primary | primary | 4 | null | 37468 | using where; using temporary; using filesort | | 1 | simple | employees | ref | index_employees_on_department_id | index_employees_on_department_id | 5 | development_db.departments.id | 5 | using | | 1 | simple | emails | | index_emails_on_emailable_id_and_emailable_type | null | null | null | 10278 | range checked each record (index map: 0x2) | +----+-------------+-------------+-------+-------------------------------------------------+----------------------------------+---------+-------------------------------+-------+------------------------------------------------+
the index on emails
is, then, not being used. index used when join emails
departments
or employees
, not both @ once.
why this? can this? there more efficient way query desired data?
it might aggregation first before joins:
select d.*, e.employees_count, em.emails_count d left outer join (select e.department_id, count(*) employees_count employees e e.is_employed = true group e.department_id ) e on e.department_id = d.id left outer join (select department_id, count(distinct id) emails_count (select em.emailable_id department_id, em.id emails em em.emailable_type = 'department' union select e.department_id, em.id emails em join employees e on em.emailable_id = e.id , em.emailable_type = 'employee' ) ee group department_id ) em on em.department_id = d.id left outer join order emails_count desc limit 20;
you want index on emails(emailable_id, emailable_type, id)
, on emails(emailable_type, emailable_id, id)
.
Comments
Post a Comment