我一直在使用数据库很长一段时间,但我是查询优化的新手。我有以下查询(其中一些代码生成):
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
这很慢。在我的开发服务器上运行大约需要一分钟,在生产服务器上,有更多数据,我甚至无法完成。这是EXPLAIN
的样子:
http://i.stack.imgur.com/eR6lq.png
我知道EXPLAIN
的基础知识。我知道NULL
下的所有内容都有key
以外的其他内容。但总的来说,我不知道我的查询有多少改进空间。我知道Using temporary; Using filesort
下的Extra
不好,但我不知道该怎么办。
答案 0 :(得分:2)
您的大多数JOIN
字段看起来都没有索引。确保用作JOIN
键的每个字段在两个表上都有索引。
有23个连接,看起来只有2个相关索引,可以预期性能不佳。
如果没有要引用的索引,查询引擎会检查两个表中的每一行来比较它们,这显然效率很低。
修改强>
例如,在您的查询中,您有
JOIN customer c ON a.customer_id = c.id
确保您在a.customer_id
AND customer.id
上有索引。在两个表上都有索引(在JOIN
ed字段上)将以指数方式加快查询速度。
答案 1 :(得分:1)
除了@JNK在答案中提到的关于确保索引的内容之外,我重新构建了您的查询并在顶部添加了“STRAIGHT_JOIN”子句,该子句告诉优化器按照表格的显示顺序执行查询它
由于您的查询是基于通用导入的,要将捆绑包导入银行,我已将其移至列表的前面...这里将首先对这些记录进行资格预审,而不是查看可能的所有帐户永远不会成为结果的一部分。因此,现在,按照您开始使用的相同关系,将联接从通用导入转回到帐户。
为了便于阅读和遵循表格关系,我还将他们加入的表格下的相应JOIN / ON条件联系起来。我也做了这样,因此ON子句有Table1.ID = JoinedTable.ID ......虽然有些反转,但没有什么大不了的,知道基于连接INTO的东西是什么,只是为了更容易阅读。
因此,确保各个表在连接的任何键列上都有索引,并且从此示例查询中,确保您的GI表(别名)具有“活动”的索引,并且您的IB(别名)具有索引Is_Finished。
最后,你的WHERE子句有WHERE 1 AND ...没有“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