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

Popular posts from this blog

css - SVG using textPath a symbol not rendering in Firefox -

Java 8 + Maven Javadoc plugin: Error fetching URL -

node.js - How to abort query on demand using Neo4j drivers -