Оптимизация запросов MySQL и EXPLAIN для нуба - PullRequest
1 голос
/ 08 февраля 2011

Я давно работаю с базами данных, но я новичок в оптимизации запросов.У меня есть следующий запрос (часть сгенерированный кодом):

SELECT DISTINCT COALESCE(gi.start_time, '') start_time,
COALESCE(b.name, '') bank,
COALESCE(a.id, '') account_id,
COALESCE(a.account_number, '') account_number,
COALESCE(at.code, '') account_type,
COALESCE(a.open_date, '') open_date,
COALESCE(a.interest_rate, '') interest_rate,
COALESCE(a.maturity_date, '') maturity_date,
COALESCE(a.opening_balance, '') opening_balance,
COALESCE(a.has_e_statement, '') has_e_statement,
COALESCE(a.has_bill_pay, '') has_bill_pay,
COALESCE(a.has_overdraft_protection, '') has_overdraft_protection,
COALESCE(a.balance, '') balance,
COALESCE(a.business_or_personal, '') business_or_personal,
COALESCE(a.cumulative_balance, '') cumulative_balance,
COALESCE(c.customer_number, '') customer_number,
COALESCE(c.social_security_number, '') social_security_number,
COALESCE(c.name, '') customer_name,
COALESCE(c.phone, '') phone,
COALESCE(c.deceased, '') deceased,
COALESCE(c.do_not_mail, '') do_not_mail,
COALESCE(cdob.date_of_birth, '') date_of_birth,
COALESCE(ad.line1, '') line1,
COALESCE(ad.line2, '') line2,
COALESCE(ad.city, '') city,
COALESCE(s.name, '') state,
COALESCE(ad.zip, '') zip,
COALESCE(o.officer_number, '') officer_number,
COALESCE(o.name, '') officer_name,
COALESCE(po.line1, '') po_box,
COALESCE(po.city, '') po_city,
COALESCE(po_state.name, '') po_state,
COALESCE(po.zip, '') zip,
COALESCE(br.number, '') branch_number,
COALESCE(cd_type.code, '') cd_type,
COALESCE(mp.product_number, '') macatawa_product_number,
COALESCE(mp.product_name, '') macatawa_product_name,
COALESCE(pt.name, '') macatawa_product_type,
COALESCE(hhsc.name, '') harte_hanks_service_category,
COALESCE(mp.hoh_hierarchy, '') hoh_hierarchy,
COALESCE(cft.name, '') core_file_type,
COALESCE(oa.line1, '') original_address_line1,
COALESCE(oa.line2, '') original_address_line2,
COALESCE(uc.code, '') use_class
            FROM account a
            JOIN customer c ON a.customer_id = c.id
            JOIN officer o ON a.officer_id = o.id
            JOIN account_address aa ON aa.account_id = a.id
       LEFT JOIN account_po_box apb ON apb.account_id = a.id                
            JOIN address ad ON aa.address_id = ad.id
            JOIN original_address oa ON oa.address_id = ad.id
       LEFT JOIN address po ON apb.address_id = po.id
            JOIN state s ON s.id = ad.state_id
       LEFT JOIN state po_state ON po_state.id = po.state_id
       LEFT JOIN branch br ON a.branch_id = br.id
            JOIN account_import ai ON a.account_import_id = ai.id
            JOIN generic_import gi ON gi.id = ai.generic_import_id
            JOIN import_bundle ib ON gi.import_bundle_id = ib.id
            JOIN bank b ON b.id = ib.bank_id
       LEFT JOIN customer_date_of_birth cdob ON cdob.customer_id = c.id
       LEFT JOIN cd_type ON a.cd_type_id = cd_type.id
       LEFT JOIN account_macatawa_product amp ON amp.account_id = a.id
       LEFT JOIN macatawa_product mp ON mp.id = amp.macatawa_product_id
       LEFT JOIN product_type pt ON pt.id = mp.product_type_id
       LEFT JOIN harte_hanks_service_category hhsc
            ON hhsc.id = mp.harte_hanks_service_category_id
       LEFT JOIN core_file_type cft ON cft.id = mp.core_file_type_id
       LEFT JOIN use_class uc ON a.use_class_id = uc.id
       LEFT JOIN account_type at ON a.account_type_id = at.id

         WHERE 1
           AND gi.active = 1
           AND b.id = 8 AND ib.is_finished = 1

        ORDER BY a.id
           LIMIT 10

И это довольно медленно.На моем dev-сервере требуется около минуты для запуска, а на моем производственном сервере, где есть больше данных, я даже не могу их завершить.Вот как выглядит EXPLAIN:

http://i.stack.imgur.com/eR6lq.png

Я знаю основы EXPLAIN.Я знаю, что хорошо, что у меня есть что-то кроме NULL для всего под key.Но в целом я не знаю, сколько места для улучшения имеет мой запрос.Я знаю, что Using temporary; Using filesort под Extra - это плохо, но я понятия не имею, что с этим делать.

Ответы [ 2 ]

2 голосов
/ 08 февраля 2011

Похоже, у вас нет индексов в большинстве ваших полей JOIN.Убедитесь, что каждое поле , которое вы используете в качестве ключа JOIN, имеет индекс для обеих таблиц.

При 23 соединениях и том, что похоже только на 2 релевантных индекса, можно ожидать низкой производительности.

Без индекса для ссылки механизм запросов проверяет каждую строку в обеих таблицах, чтобы сравнить их,что, очевидно, очень неэффективно.

edit:

Например, в вашем запросе вы имеете

JOIN customer c ON a.customer_id = c.id

Makeуверен, что у вас есть индекс для a.customer_id AND customer.id.Наличие индекса в обеих таблицах (в полях JOIN ed) экспоненциально ускорит запрос.

1 голос
/ 08 февраля 2011

В дополнение к тому, что @JNK упомянул в своем ответе о том, что у вас есть индексы, я реструктурировал ваш запрос и добавил в верхней части предложение "STRAIGHT_JOIN", которое сообщает оптимизатору, чтобы он выполнял запрос в том порядке, в котором представлены таблицы. это.

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

Я также связал соответствующие условия JOIN / ON непосредственно под таблицей, к которой они присоединялись, для удобства чтения и следования связям таблиц. Я также сделал так, чтобы предложение ON имело Table1.ID = JoinedTable.ID ... хотя некоторые перевернуты, а в остальном ничего страшного, зная, как что-то основано на объединении с INTO, другое просто облегчает чтение.

Итак, убедитесь, что соответствующие таблицы имеют индексы для любого ключевого столбца, к которому относится соединение, и из этого примера запроса убедитесь, что ваша таблица GI (псевдоним) имеет индекс "Active", а ваш IB (псевдоним) - индекс Is_Finished.

Наконец, в вашем предложении WHERE было WHERE 1 и ... нет цели "1", поэтому я удалил это.

SELECT STRAIGHT_JOIN DISTINCT 
      COALESCE(gi.start_time, '') start_time, 
      COALESCE(b.name, '') bank, 
      COALESCE(a.id, '') account_id, 
      COALESCE(a.account_number, '') account_number, 
      COALESCE(at.code, '') account_type, 
      COALESCE(a.open_date, '') open_date, 
      COALESCE(a.interest_rate, '') interest_rate, 
      COALESCE(a.maturity_date, '') maturity_date, 
      COALESCE(a.opening_balance, '') opening_balance, 
      COALESCE(a.has_e_statement, '') has_e_statement, 
      COALESCE(a.has_bill_pay, '') has_bill_pay, 
      COALESCE(a.has_overdraft_protection, '') has_overdraft_protection, 
      COALESCE(a.balance, '') balance, 
      COALESCE(a.business_or_personal, '') business_or_personal, 
      COALESCE(a.cumulative_balance, '') cumulative_balance, 
      COALESCE(c.customer_number, '') customer_number, 
      COALESCE(c.social_security_number, '') social_security_number, 
      COALESCE(c.name, '') customer_name, 
      COALESCE(c.phone, '') phone, 
      COALESCE(c.deceased, '') deceased, 
      COALESCE(c.do_not_mail, '') do_not_mail, 
      COALESCE(cdob.date_of_birth, '') date_of_birth, 
      COALESCE(ad.line1, '') line1, 
      COALESCE(ad.line2, '') line2, 
      COALESCE(ad.city, '') city, 
      COALESCE(s.name, '') state, 
      COALESCE(ad.zip, '') zip, 
      COALESCE(o.officer_number, '') officer_number, 
      COALESCE(o.name, '') officer_name, 
      COALESCE(po.line1, '') po_box, 
      COALESCE(po.city, '') po_city, 
      COALESCE(po_state.name, '') po_state, 
      COALESCE(po.zip, '') zip, 
      COALESCE(br.number, '') branch_number, 
      COALESCE(cd_type.code, '') cd_type, 
      COALESCE(mp.product_number, '') macatawa_product_number, 
      COALESCE(mp.product_name, '') macatawa_product_name, 
      COALESCE(pt.name, '') macatawa_product_type, 
      COALESCE(hhsc.name, '') harte_hanks_service_category, 
      COALESCE(mp.hoh_hierarchy, '') hoh_hierarchy, 
      COALESCE(cft.name, '') core_file_type, 
      COALESCE(oa.line1, '') original_address_line1, 
      COALESCE(oa.line2, '') original_address_line2, 
      COALESCE(uc.code, '') use_class             
   FROM 
      generic_import gi 
         JOIN import_bundle ib 
            ON gi.import_bundle_id = ib.id
            JOIN bank b 
               ON ib.bank_id = b.id 
         JOIN account_import ai 
            ON gi.id = ai.generic_import_id
         JOIN  account a
            ON ai.id = a.account_import_id
            JOIN customer c 
               ON a.customer_id = c.id
               LEFT JOIN customer_date_of_birth cdob 
                  ON c.id = cdob.customer_id
            JOIN officer o 
               ON a.officer_id = o.id
            LEFT JOIN branch br 
               ON a.branch_id = br.id
            LEFT JOIN cd_type 
               ON a.cd_type_id = cd_type.id
            LEFT JOIN account_macatawa_product amp 
               ON a.id = amp.account_id
               LEFT JOIN macatawa_product mp 
                  ON amp.macatawa_product_id = mp.id
                  LEFT JOIN product_type pt 
                     ON mp.product_type_id = pt.id
                  LEFT JOIN harte_hanks_service_category hhsc 
                     ON mp.harte_hanks_service_category_id = hhsc.id
                  LEFT JOIN core_file_type cft 
                     ON mp.core_file_type_id = cft.id
            LEFT JOIN use_class uc 
               ON a.use_class_id = uc.id
            LEFT JOIN account_type at 
               ON a.account_type_id = at.id
            JOIN account_address aa 
               ON a.id = aa.account_id 
               JOIN address ad 
                  ON aa.address_id = ad.id 
                  JOIN original_address oa 
                     ON ad.id = oa.address_id
                  JOIN state s 
                     ON ad.state_id = s.id 
            LEFT JOIN account_po_box apb 
               ON a.id = apb.account_id 
               LEFT JOIN address po 
                  ON apb.address_id = po.id
                  LEFT JOIN state po_state 
                     ON po.state_id = po_state.id
      WHERE 
              gi.active = 1
          AND ib.is_finished = 1
          AND b.id = 8 
      ORDER BY 
          a.id
       LIMIT 
          10 
...