Оптимизация SQL-запросов (Mysql 5.7) - PullRequest
0 голосов
/ 26 ноября 2018

У меня есть следующий запрос для выполнения в live mysql 5.7, который занимает около 7 секунд, и мы хотим сократить их время, пожалуйста, поделитесь своими мыслями

SELECT 
     COUNT(
          DISTINCT InternalInquiry.inquiry_id
     ) AS "count" 
FROM
     internal_inquiries `InternalInquiry` 
     LEFT JOIN cpml_projects `Project` 
          ON (
               Project.project_id = InternalInquiry.object_id 
               AND Project.agent_id = 159297
          ) 
     INNER JOIN clients `Client` 
          ON (
               Client.clientid = InternalInquiry.clientID
          ) 
     INNER JOIN 
          (SELECT DISTINCT 
               (InternalInquiry.inquiry_id) AS "id" 
          FROM
               internal_inquiries `InternalInquiry` 
                LEFT JOIN internal_inquiries_sharing `InternalInquirySharing` 
                    ON (
                         InternalInquiry.inquiry_id = InternalInquirySharing.inquiry_id 
                    )
          WHERE (
                    (
                      InternalInquiry.userid IN ( 399724, 420710, 438389, 535916, 535917, 541643, 541644)
                       OR InternalInquirySharing.share_with IN ( 399724, 420710, 438389, 535916, 535917, 541643, 541644)
                     ) 
               ) 
               AND  (
                    InternalInquiry.status IN (
                         1, 21, 26, 14, 4, 15, 13, 5, 16, 17, 18, 22, 25, 2, 10, 3, 19, 20, 23, 11, 12, 24, 9, 8, 28
                    )
               ) 
               AND (
                    InternalInquiry.time_added >= '2013-11-01 00:00:00' 
                    AND InternalInquiry.time_added <= '2018-11-22 23:59:59'
               )) dd 
          ON dd.id = InternalInquiry.inquiry_id 
WHERE (
          InternalInquiry.firmstate != 'deleted'
     ) 
     AND (
          InternalInquiry.status IN (
               1, 21, 26, 14, 4, 15, 13, 5, 16, 17, 18, 22, 25, 2, 10, 3, 19, 20, 23, 11, 12, 24, 9, 8, 28
          )
     ) 
     AND (
          InternalInquiry.time_added >= '2013-11-01 00:00:00' 
          AND InternalInquiry.time_added <= '2018-11-22 23:59:59'
     ) 
     AND (
           Client.client_status != 1 AND
           Client.client_agency = 159297
     )

План выполнения следующим образом:

 id  select_type  table                   partitions  type    possible_keys                                                                                                         key                               key_len  ref                                       rows  filtered  Extra                         
------  -----------  ----------------------  ----------  ------  --------------------------------------------------------------------------------------------------------------------  --------------------------------  -------  --------------------------------------  ------  --------  ------------------------------
     1  PRIMARY      <derived2>              (NULL)      ALL     (NULL)                                                                                                                (NULL)                            (NULL)   (NULL)                                  143661    100.00  (NULL)                        
     1  PRIMARY      InternalInquiry         (NULL)      eq_ref  PRIMARY,clientID,time_added,firmstate,search_inquiry_basic_index                                                      PRIMARY                           4        dd.id                                        1     12.50  Using where                   
     1  PRIMARY      Client                  (NULL)      eq_ref  PRIMARY,client_agency,client_status,com_1                                                                             PRIMARY                           4        InternalInquiry.clientID                     1     25.00  Using where                   
     1  PRIMARY      Project                 (NULL)      ref     project_id                                                                                                            project_id                        5        InternalInquiry.object_id                    1    100.00  Using where                   
     2  DERIVED      InternalInquiry         (NULL)      ALL     PRIMARY,clientID,userid,object_type,next_status_wanted,time_added,firmstate,search_inquiry_basic_index,idx_object_id  (NULL)                            (NULL)   (NULL)                                  544996     25.00  Using where; Using temporary  
     2  DERIVED      InternalInquirySharing  (NULL)      ref     internal_inquiries_sharing_UN,inquiry_id                                                                               internal_inquiries_sharing_UN    5        InternalInquiry.inquiry_id                   1    100.00  Using where; Using index      

Я делюсь информацией об индексах для основной таблицы

internal_inquiries

Ответы [ 2 ]

0 голосов
/ 26 ноября 2018

Для начала вы только получаете счет, но никогда не используете INNER JOIN на таблице проектов, так что вам это не нужно.Я бы удалил это.Ваш внутренний и внешний запросы ОБА одинаково проверяют статус, дату и время.Так что я бы удалил это изнутри и просто сохранил критерии user_id / ShareWith.Затем я переместил критерии WHERE клиента в предложение JOIN этого экземпляра.

Упростил дату до даты 2013-11-01, поскольку без времени подразумевается 00:00:00.Также измените время окончания на МЕНЬШЕ, чем 2018-11-23, что подразумевает включение 2018-11-22 до 11:59:59 pm.

Наконец, ваш внутренний запрос к общему контексту.Мы знаем, что это обязательное присоединение через INNER, и, похоже, вы заботитесь только о конкретных пользователях в запросе ИЛИ поделились им.Поэтому я немного изменил левое соединение на общем доступе, но только для пользователя OTHER SHARE WITH и перешел к предложению where

SELECT 
      COUNT( DISTINCT II.inquiry_id ) AS "count" 
   FROM
      internal_inquiries II 
         INNER JOIN clients `Client` 
            ON II.clientID = C.clientid
           AND C.client_agency = 159297
           AND C.client_status != 1 
         LEFT JOIN internal_inquiries_sharing IIS
            ON II.inquiry_id = SharedUser.inquiry_id 
            AND IIS.share_with IN ( 399724, 420710, 438389, 535916, 535917, 541643, 541644 )
   WHERE 
          II.firmstate != 'deleted'
      AND II.status IN ( 1, 21, 26, 14, 4, 15, 13, 5, 16, 17, 18, 22, 25, 2, 10, 3, 19, 20, 23, 11, 12, 24, 9, 8, 28 )
      AND II.time_added >= '2013-11-01' 
      AND II.time_added < '2018-11-23'
      AND ( II.userid IN ( 399724, 420710, 438389, 535916, 535917, 541643, 541644)
            OR IIS.Inquery_ID IS NOT NULL )

Кроме того, я бы обеспечил наличие следующих индексов в соответствующих таблицах

table                       index
Internal_Inquiries          ( time_added, status, user_id, firmstate, inquiry_id )
Client                      ( clientID, Client_Agency, client_status )
internal_inquiries_sharing  ( share_with, inquiry_id )

Поскольку внешний запрос предварительно ограничен на основе статуса и времени, мы знаем, что получаем ВСЕХ возможных пользователей, и нам не нужно добавлять эти дополнительные критерии в объединение для общих ресурсов.ПОСЛЕДНЯЯ часть предложения WHERE будет применяться для одного пользователя ИЛИ пользователя, найденного в качестве общего ресурса.

Последнее возможное добавление к запросу будет добавление ключевого слова STRAIGHT_JOIN, специфичного для MySQL, через

SELECT STRAIGHT_JOIN  Count( distinct ….
0 голосов
/ 26 ноября 2018

Основная проблема заключается в том, что у вас нет индекса, охватывающего основные критерии как внутреннего, так и внешнего запроса в основной таблице.Там может быть несколько более точной настройки, но это должно быть хорошее начало:

CREATE INDEX ix_internal_inquiries_status_timeadded
    ON internal_inquiries
    (status, time_added);

Кроме того, версии с inquiry_id и / или firmstate могут иметь значение, но это должно быть проверено:

CREATE INDEX ix_internal_inquiries_inquiryid_status_timeadded, firmstate
    ON internal_inquiries
    (inquiry_id, status, time_added, firmstate);

Просто попробуйте несколько комбинаций и посмотрите, получится ли это еще дальше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...