MySQL оптимизировать медленно выполняющийся запрос при использовании оператора not equals - PullRequest
0 голосов
/ 13 марта 2020

Я использую MySQL 5.7 и у меня следующий запрос занимает более 8 сек c для выполнения, что слишком медленно.

explain select distinct `jobs`.*
      , CASE WHEN jobs.alt_company_name IS NOT NULL OR job_files.path IS NOT NULL 
          THEN job_files.path 
          ELSE company_files.path 
        END AS logo_path
      , `applications`.`created_at` as `application_date` 
from `jobs` 
inner join `job_status` on `job_status`.`job_id` = `jobs`.`id` 
inner join `recruiters` on `recruiters`.`id` = `jobs`.`recruiter_id`
inner join `companies` on `companies`.`id` = `recruiters`.`company_id` 
inner join `locations` on `locations`.`id` = `jobs`.`location_id` 
inner join `location_name` on `location_name`.`location_id` = `locations`.`id` 
inner join `job_language` on `job_language`.`job_id` = `jobs`.`id` 
inner join `languages` on `languages`.`id` = `job_language`.`language_id` 
inner join `job_industry` on `job_industry`.`job_id` = `jobs`.`id` 
left join `job_salary` on `job_salary`.`job_id` = `jobs`.`id` 
left join (SELECT fileable_id, MIN(created_at) as min_created_at
            FROM files WHERE file_type = "JobLogo" AND fileable_type = "App\\Job"
            GROUP BY fileable_id) AS subquery_one on `subquery_one`.`fileable_id` = `jobs`.`id` 
left join `files` as `job_files` on `job_files`.`fileable_id` = `subquery_one`.`fileable_id` and `job_files`.`created_at` = `subquery_one`.`min_created_at` 
left join (SELECT fileable_id, MIN(created_at) as min_created_at
            FROM files WHERE file_type = "CompanyLogo" AND fileable_type = "App\\Company"
            GROUP BY fileable_id) AS subquery_two on `subquery_two`.`fileable_id` = `companies`.`id` 
left join `files` as `company_files` on `company_files`.`fileable_id` = `subquery_two`.`fileable_id` and `company_files`.`created_at` = `subquery_two`.`min_created_at` 
left join `job_shortlist` on `job_shortlist`.`job_id` = `jobs`.`id` and `job_shortlist`.`jobseeker_id` is NULL 
left join `applications` on `applications`.`job_id` = `jobs`.`id` and `applications`.`jobseeker_id` is NULL 
where (`languages`.`id` in ('1') or `languages`.`parent_id` in ('1')) 
and `job_industry`.`industry_id` in ('1', '5','6') 
and `jobs`.`contract_type_id` in ('3') 
and `jobs`.`contract_hour_id` in ('1') 
and `jobs`.`id` <> 6 
and `applications`.`id` is NULL 
and `jobs`.`start_at` <= '2020-03-13 15:06:29' 
and `jobs`.`end_at` >= '2020-03-13 15:06:29' 
and `jobs`.`status_id` = 4 
order by jobs.start_at desc, jobs.id desc limit 4

Объяснение результатов:

+----+-------------+---------------+------------+--------+-----------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------+---------+-------------------------------------+------+----------+---------------------------------------------------------------------+
| id | select_type | table         | partitions | type   | possible_keys                                                                                                                                 | key                                     | key_len | ref                                 | rows | filtered | Extra                                                               |
+----+-------------+---------------+------------+--------+-----------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------+---------+-------------------------------------+------+----------+---------------------------------------------------------------------+
|  1 | PRIMARY     | jobs          | NULL       | range  | PRIMARY,jobs_status_id_foreign,jobs_recruiter_id_foreign,jobs_contract_type_id_foreign,jobs_contract_hour_id_foreign,jobs_location_id_foreign | jobs_status_id_foreign                  | 8       | NULL                                |    6 |    16.67 | Using index condition; Using where; Using temporary; Using filesort |
|  1 | PRIMARY     | job_language  | NULL       | ref    | PRIMARY,job_language_language_id_foreign                                                                                                      | PRIMARY                                 | 4       | testjobsdb.jobs.id                  |    1 |   100.00 | Using index                                                         |
|  1 | PRIMARY     | languages     | NULL       | eq_ref | PRIMARY,languages_parent_id_index                                                                                                             | PRIMARY                                 | 4       | testjobsdb.job_language.language_id |    1 |   100.00 | Using where                                                         |
|  1 | PRIMARY     | job_industry  | NULL       | eq_ref | PRIMARY,job_industry_industry_id_foreign                                                                                                      | PRIMARY                                 | 8       | testjobsdb.jobs.id,const            |    1 |   100.00 | Using index                                                         |
|  1 | PRIMARY     | jobs          | NULL       | eq_ref | PRIMARY,jobs_status_id_foreign                                                                                                                | PRIMARY                                 | 4       | testjobsdb.jobs.id                  |    1 |   100.00 | NULL                                                                |
|  1 | PRIMARY     | job_salary    | NULL       | ref    | PRIMARY                                                                                                                                       | PRIMARY                                 | 4       | testjobsdb.jobs.id                  |    1 |   100.00 | Using index                                                         |
|  1 | PRIMARY     | recruiters    | NULL       | eq_ref | PRIMARY,recruiters_company_id_foreign                                                                                                         | PRIMARY                                 | 4       | testjobsdb.jobs.recruiter_id        |    1 |   100.00 | NULL                                                                |
|  1 | PRIMARY     | companies     | NULL       | eq_ref | PRIMARY                                                                                                                                       | PRIMARY                                 | 4       | testjobsdb.recruiters.company_id    |    1 |   100.00 | Using index                                                         |
|  1 | PRIMARY     | status_types  | NULL       | eq_ref | PRIMARY                                                                                                                                       | PRIMARY                                 | 4       | testjobsdb.jobs.status_id           |    1 |   100.00 | Using index                                                         |
|  1 | PRIMARY     | locations     | NULL       | eq_ref | PRIMARY                                                                                                                                       | PRIMARY                                 | 4       | testjobsdb.jobs.location_id         |    1 |   100.00 | Using index                                                         |
|  1 | PRIMARY     | t0            | NULL       | eq_ref | PRIMARY                                                                                                                                       | PRIMARY                                 | 4       | testjobsdb.jobs.location_id         |    1 |   100.00 | NULL                                                                |
|  1 | PRIMARY     | <derived2>    | NULL       | ref    | <auto_key1>                                                                                                                                   | <auto_key1>                             | 5       | testjobsdb.jobs.id                  |    2 |   100.00 | NULL                                                                |
|  1 | PRIMARY     | job_files     | NULL       | ALL    | NULL                                                                                                                                          | NULL                                    | NULL    | NULL                                | 1712 |   100.00 | Using where; Using join buffer (Block Nested Loop)                  |
|  1 | PRIMARY     | <derived3>    | NULL       | ref    | <auto_key1>                                                                                                                                   | <auto_key1>                             | 5       | testjobsdb.recruiters.company_id    |    2 |   100.00 | NULL                                                                |
|  1 | PRIMARY     | company_files | NULL       | ALL    | NULL                                                                                                                                          | NULL                                    | NULL    | NULL                                | 1712 |   100.00 | Using where; Using join buffer (Block Nested Loop)                  |
|  1 | PRIMARY     | job_shortlist | NULL       | eq_ref | PRIMARY,job_shortlist_job_id_unique                                                                                                           | PRIMARY                                 | 8       | const,testjobsdb.jobs.id            |    1 |   100.00 | Using where; Using index                                            |
|  1 | PRIMARY     | applications  | NULL       | eq_ref | applications_job_id_jobseeker_id_unique,applications_jobseeker_id_foreign                                                                     | applications_job_id_jobseeker_id_unique | 8       | testjobsdb.jobs.id,const            |    1 |    25.00 | Using where; Not exists                                             |
|  1 | PRIMARY     | t4            | NULL       | ref    | locations_admin4_feature_code_index                                                                                                           | locations_admin4_feature_code_index     | 126     | testjobsdb.t0.admin4,const          |    3 |   100.00 | Using index; Distinct                                               |
|  1 | PRIMARY     | t3            | NULL       | ref    | locations_admin3_feature_code_index                                                                                                           | locations_admin3_feature_code_index     | 126     | testjobsdb.t0.admin3,const          |    4 |   100.00 | Using index; Distinct                                               |
|  1 | PRIMARY     | t2            | NULL       | ref    | locations_admin2_feature_code_index                                                                                                           | locations_admin2_feature_code_index     | 366     | testjobsdb.t0.admin2,const          |   12 |   100.00 | Using index; Distinct                                               |
|  1 | PRIMARY     | t1            | NULL       | ref    | locations_admin1_feature_code_index                                                                                                           | locations_admin1_feature_code_index     | 126     | testjobsdb.t0.admin1,const          |   70 |   100.00 | Using index; Distinct                                               |
|  3 | DERIVED     | files         | NULL       | ALL    | NULL                                                                                                                                          | NULL                                    | NULL    | NULL                                | 1712 |     1.11 | Using where; Using temporary; Using filesort                        |
|  2 | DERIVED     | files         | NULL       | ALL    | NULL                                                                                                                                          | NULL                                    | NULL    | NULL                                | 1712 |     1.11 | Using where; Using temporary; Using filesort                        |
+----+-------------+---------------+------------+--------+-----------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------+---------+-------------------------------------+------+----------+---------------------------------------------------------------------+
23 rows in set, 1 warning (8.30 sec)

Если я удаляю условие where and jobs.id <> 6 или удаляем оставленные подзапросы, присоединения, запросы выполняются в соответствии с 0.11 se c

explain select distinct `jobs`.*
      , CASE WHEN jobs.alt_company_name IS NOT NULL OR job_files.path IS NOT NULL 
          THEN job_files.path 
          ELSE company_files.path 
        END AS logo_path
      , `applications`.`created_at` as `application_date` 
from `jobs` 
inner join `job_status` on `job_status`.`job_id` = `jobs`.`id` 
inner join `recruiters` on `recruiters`.`id` = `jobs`.`recruiter_id`
inner join `companies` on `companies`.`id` = `recruiters`.`company_id` 
inner join `locations` on `locations`.`id` = `jobs`.`location_id` 
inner join `location_name` on `location_name`.`location_id` = `locations`.`id` 
inner join `job_language` on `job_language`.`job_id` = `jobs`.`id` 
inner join `languages` on `languages`.`id` = `job_language`.`language_id` 
inner join `job_industry` on `job_industry`.`job_id` = `jobs`.`id` 
left join `job_salary` on `job_salary`.`job_id` = `jobs`.`id` 
left join (SELECT fileable_id, MIN(created_at) as min_created_at
            FROM files WHERE file_type = "JobLogo" AND fileable_type = "App\\Job"
            GROUP BY fileable_id) AS subquery_one on `subquery_one`.`fileable_id` = `jobs`.`id` 
left join `files` as `job_files` on `job_files`.`fileable_id` = `subquery_one`.`fileable_id` and `job_files`.`created_at` = `subquery_one`.`min_created_at` 
left join (SELECT fileable_id, MIN(created_at) as min_created_at
            FROM files WHERE file_type = "CompanyLogo" AND fileable_type = "App\\Company"
            GROUP BY fileable_id) AS subquery_two on `subquery_two`.`fileable_id` = `companies`.`id` 
left join `files` as `company_files` on `company_files`.`fileable_id` = `subquery_two`.`fileable_id` and `company_files`.`created_at` = `subquery_two`.`min_created_at` 
left join `job_shortlist` on `job_shortlist`.`job_id` = `jobs`.`id` and `job_shortlist`.`jobseeker_id` is NULL 
left join `applications` on `applications`.`job_id` = `jobs`.`id` and `applications`.`jobseeker_id` is NULL 
where (`languages`.`id` in ('1') or `languages`.`parent_id` in ('1')) 
and `job_industry`.`industry_id` in ('1') 
and `jobs`.`contract_type_id` in ('3') 
and `jobs`.`contract_hour_id` in ('1') 
and `applications`.`id` is NULL 
and `jobs`.`start_at` <= '2020-03-13 15:06:29' 
and `jobs`.`end_at` >= '2020-03-13 15:06:29' 
and `jobs`.`status_id` = 4 
order by jobs.start_at desc, jobs.id desc limit 4

Объясните результаты:

+----+-------------+---------------+------------+--------+-----------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------+---------+-------------------------------------+------+----------+----------------------------------------------------+
| id | select_type | table         | partitions | type   | possible_keys                                                                                                                                 | key                                     | key_len | ref                                 | rows | filtered | Extra                                              |
+----+-------------+---------------+------------+--------+-----------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------+---------+-------------------------------------+------+----------+----------------------------------------------------+
|  1 | PRIMARY     | jobs          | NULL       | ALL    | PRIMARY,jobs_status_id_foreign,jobs_recruiter_id_foreign,jobs_contract_type_id_foreign,jobs_contract_hour_id_foreign,jobs_location_id_foreign | NULL                                    | NULL    | NULL                                |    6 |    16.67 | Using where; Using temporary; Using filesort       |
|  1 | PRIMARY     | job_language  | NULL       | ref    | PRIMARY,job_language_language_id_foreign                                                                                                      | PRIMARY                                 | 4       | testjobsdb.jobs.id                  |    1 |   100.00 | Using index                                        |
|  1 | PRIMARY     | languages     | NULL       | eq_ref | PRIMARY,languages_parent_id_index                                                                                                             | PRIMARY                                 | 4       | testjobsdb.job_language.language_id |    1 |   100.00 | Using where                                        |
|  1 | PRIMARY     | job_industry  | NULL       | eq_ref | PRIMARY,job_industry_industry_id_foreign                                                                                                      | PRIMARY                                 | 8       | testjobsdb.jobs.id,const            |    1 |   100.00 | Using index                                        |
|  1 | PRIMARY     | jobs          | NULL       | eq_ref | PRIMARY,jobs_status_id_foreign                                                                                                                | PRIMARY                                 | 4       | testjobsdb.jobs.id                  |    1 |   100.00 | NULL                                               |
|  1 | PRIMARY     | job_salary    | NULL       | ref    | PRIMARY                                                                                                                                       | PRIMARY                                 | 4       | testjobsdb.jobs.id                  |    1 |   100.00 | Using index                                        |
|  1 | PRIMARY     | recruiters    | NULL       | eq_ref | PRIMARY,recruiters_company_id_foreign                                                                                                         | PRIMARY                                 | 4       | testjobsdb.jobs.recruiter_id        |    1 |   100.00 | NULL                                               |
|  1 | PRIMARY     | companies     | NULL       | eq_ref | PRIMARY                                                                                                                                       | PRIMARY                                 | 4       | testjobsdb.recruiters.company_id    |    1 |   100.00 | Using index                                        |
|  1 | PRIMARY     | status_types  | NULL       | eq_ref | PRIMARY                                                                                                                                       | PRIMARY                                 | 4       | testjobsdb.jobs.status_id           |    1 |   100.00 | Using index                                        |
|  1 | PRIMARY     | locations     | NULL       | eq_ref | PRIMARY                                                                                                                                       | PRIMARY                                 | 4       | testjobsdb.jobs.location_id         |    1 |   100.00 | Using index                                        |
|  1 | PRIMARY     | t0            | NULL       | eq_ref | PRIMARY                                                                                                                                       | PRIMARY                                 | 4       | testjobsdb.jobs.location_id         |    1 |   100.00 | NULL                                               |
|  1 | PRIMARY     | <derived2>    | NULL       | ref    | <auto_key1>                                                                                                                                   | <auto_key1>                             | 5       | testjobsdb.jobs.id                  |    2 |   100.00 | NULL                                               |
|  1 | PRIMARY     | job_files     | NULL       | ALL    | NULL                                                                                                                                          | NULL                                    | NULL    | NULL                                | 1712 |   100.00 | Using where; Using join buffer (Block Nested Loop) |
|  1 | PRIMARY     | <derived3>    | NULL       | ref    | <auto_key1>                                                                                                                                   | <auto_key1>                             | 5       | testjobsdb.recruiters.company_id    |    2 |   100.00 | NULL                                               |
|  1 | PRIMARY     | company_files | NULL       | ALL    | NULL                                                                                                                                          | NULL                                    | NULL    | NULL                                | 1712 |   100.00 | Using where; Using join buffer (Block Nested Loop) |
|  1 | PRIMARY     | job_shortlist | NULL       | eq_ref | PRIMARY,job_shortlist_job_id_unique                                                                                                           | PRIMARY                                 | 8       | const,testjobsdb.jobs.id            |    1 |   100.00 | Using where; Using index                           |
|  1 | PRIMARY     | applications  | NULL       | eq_ref | applications_job_id_jobseeker_id_unique,applications_jobseeker_id_foreign                                                                     | applications_job_id_jobseeker_id_unique | 8       | testjobsdb.jobs.id,const            |    1 |    25.00 | Using where; Not exists                            |
|  1 | PRIMARY     | t4            | NULL       | ref    | locations_admin4_feature_code_index                                                                                                           | locations_admin4_feature_code_index     | 126     | testjobsdb.t0.admin4,const          |    3 |   100.00 | Using index; Distinct                              |
|  1 | PRIMARY     | t3            | NULL       | ref    | locations_admin3_feature_code_index                                                                                                           | locations_admin3_feature_code_index     | 126     | testjobsdb.t0.admin3,const          |    4 |   100.00 | Using index; Distinct                              |
|  1 | PRIMARY     | t2            | NULL       | ref    | locations_admin2_feature_code_index                                                                                                           | locations_admin2_feature_code_index     | 366     | testjobsdb.t0.admin2,const          |   12 |   100.00 | Using index; Distinct                              |
|  1 | PRIMARY     | t1            | NULL       | ref    | locations_admin1_feature_code_index                                                                                                           | locations_admin1_feature_code_index     | 126     | testjobsdb.t0.admin1,const          |   70 |   100.00 | Using index; Distinct                              |
|  3 | DERIVED     | files         | NULL       | ALL    | NULL                                                                                                                                          | NULL                                    | NULL    | NULL                                | 1712 |     1.11 | Using where; Using temporary; Using filesort       |
|  2 | DERIVED     | files         | NULL       | ALL    | NULL                                                                                                                                          | NULL                                    | NULL    | NULL                                | 1712 |     1.11 | Using where; Using temporary; Using filesort       |
+----+-------------+---------------+------------+--------+-----------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------+---------+-------------------------------------+------+----------+----------------------------------------------------+
23 rows in set, 1 warning (0.11 sec)

Как я могу оптимизировать этот запрос. Любые советы, советы, советы очень ценятся.

Ответы [ 2 ]

1 голос
/ 13 марта 2020

Не ответ; слишком долго для комментария.

Я ценю, что сервер делает свое дело, но мне легче читать, когда написано так ...

Я прокомментировал пару сомнительные строки в вашем коде ...

SELECT DISTINCT j.*
              , CASE WHEN j.alt_company_name IS NOT NULL OR jf.path IS NOT NULL 
                     THEN jf.path 
                     ELSE cf.path 
                     END logo_path
              , a.created_at application_date 
           FROM jobs j
           JOIN job_status js
             ON js.job_id = j.id 
           JOIN recruiters r
             ON r.id = j.recruiter_id
           JOIN companies c
             ON c.id = r.company_id 
           JOIN locations l
             ON l.id = j.location_id 
           JOIN location_name ln
             ON ln.location_id = l.id 
           JOIN job_language jx
             ON jx.job_id = j.id 
           JOIN languages x
             ON x.id = jx.language_id 
           JOIN job_industry ji
             ON ji.job_id = j.id 
           JOIN job_salary js
             ON js.job_id = j.id 
           LEFT 
           JOIN 
              ( SELECT fileable_id
                     , MIN(created_at) min_created_at
                  FROM files 
                 WHERE file_type = "JobLogo" 
                   AND fileable_type = "App\\Job"
                 GROUP 
                    BY fileable_id
               ) m 
              ON m.fileable_id = j.id
            LEFT 
            JOIN files jf 
              ON jf.fileable_id = m.fileable_id 
             AND jf.created_at = m.min_created_at 
            LEFT 
            JOIN 
               ( SELECT fileable_id
                      , MIN(created_at) min_created_at
                   FROM files 
                  WHERE file_type = "CompanyLogo" 
                    AND fileable_type = "App\\Company"
                  GROUP 
                     BY fileable_id
               ) n
              ON n.fileable_id = c.id 
            LEFT 
            JOIN files cf
              ON cf.fileable_id = n.fileable_id 
             AND cf.created_at = n.min_created_at 
            LEFT 
            JOIN job_shortlist 
              ON job_shortlist.job_id = j.id 
             AND job_shortlist.jobseeker_id is NULL -- Was this meant to be in the WHERE clause?
            LEFT 
            JOIN applications a
              ON a.job_id = j.id 
             AND a.jobseeker_id is NULL -- and this too??
           WHERE 1 IN(x.id,x.parent_id) 
             AND ji.industry_id in (1) 
             AND j.contract_type_id in (3) 
             AND j.contract_hour_id in (1) 
             AND j.id <> 6 
             AND a.id IS NULL 
             AND j.start_at <= '2020-03-13 15:06:29' 
             AND j.end_at >= '2020-03-13 15:06:29' 
             AND j.status_id = 4 
           ORDER 
              BY j.start_at DESC
               , j.id DESC 
           LIMIT 4
0 голосов
/ 13 марта 2020

Это похоже на шаблон "взорвать-взорвать" - JOIN множество таблиц вместе, затем устранить дублирование (DISTINCT'). Также LIMIT нельзя сделать до тех пор, пока все JOINs; это может быть совершенно неэффективно.

Итак, попробуйте переписать его примерно следующим образом:

SELECT ...   -- no DISTINCT
    FROM ( SELECT jobs.id
            FROM jobs
            WHERE ...
            ORDER BY ...
            LIMIT 4 ) AS j
    JOIN ... -- all the other tables, plus `jobs` again
    ORDER BY ...   -- repeated, but no LIMIT repetition

files нужен этот составной (и составной) индекс:

INDEX(file_type, fileable_type, fileable_id, created_at)
...