noob的MySQL查询优化与解释

noob的MySQL查询优化与解释,sql,mysql,database,query-optimization,Sql,Mysql,Database,Query Optimization,我已经使用数据库很长时间了,但我对查询优化还不熟悉。我有以下查询(其中一些是生成的代码): 而且相当慢。在我的开发服务器上运行大约需要一分钟,而在我的生产服务器上,那里有更多的数据,我甚至无法让它完成。下面是一个解释的样子: 我知道解释的基本知识。我知道,对于键下的所有内容,除了NULL之外,我还有别的东西是很好的。但总的来说,我不知道我的查询还有多少改进空间。我知道使用临时的;在Extra下使用filesort是不好的,但我不知道该怎么办。看起来您的大多数JOIN字段上都没有索引。确保用作J

我已经使用数据库很长时间了,但我对查询优化还不熟悉。我有以下查询(其中一些是生成的代码):

而且相当慢。在我的开发服务器上运行大约需要一分钟,而在我的生产服务器上,那里有更多的数据,我甚至无法让它完成。下面是一个
解释
的样子:


我知道
解释的基本知识。我知道,对于
键下的所有内容,除了
NULL
之外,我还有别的东西是很好的。但总的来说,我不知道我的查询还有多少改进空间。我知道
使用临时的;在
Extra
下使用filesort
是不好的,但我不知道该怎么办。

看起来您的大多数
JOIN
字段上都没有索引。确保用作
JOIN
键的每个字段在两个表上都有索引

由于有23个连接,而且看起来只有2个相关索引,因此性能可能会很差

由于没有可引用的索引,查询引擎将检查两个表中的每一行以比较它们,这显然是非常低效的

编辑:

例如,在查询中

在a.customer\u id=c.id上加入客户c


确保在
a.customer\u id
上有索引。在两个表上都有一个索引(在
JOIN
ed字段上)将以指数方式加快查询速度。

除了@JNK在其回答中提到的关于确保您有索引的内容外,我还重新构造了您的查询并添加了“直联”子句,它告诉优化器按照向其显示表的顺序执行查询

由于您的查询是基于通用导入的,为了将bundle导入银行,我将它们移到了列表的前面。。。where将首先对这些记录进行资格预审,而不是查看可能永远不会成为结果一部分的所有帐户。因此,连接现在从通用导入反转回帐户,并遵循与开始时相同的关系

为了可读性和下表关系,我还将各自的连接/打开条件直接关联到它们所连接的表下。我还将其设置为使ON子句具有Table1.ID=JoinedTable.ID。。。虽然有些是相反的,或者没有什么大不了的,但是知道一些东西是如何基于连接到另一个的,只会让可读性更容易

因此,确保各个表在连接的任何键列上都有索引,并且从这个示例查询中,确保您的GI表(别名)在“Active”上有索引,并且您的IB(别名)在“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 

您在要加入的表上有索引吗?我在我要加入的大多数表的某些列上有索引。@jason swett-此查询中的相关列就是您要加入的列。请参阅下面我的答案。解释结果是来自生产服务器还是开发服务器?在对所有涉及的表执行
分析表之后,您能否在生产服务器上尝试
解释
?正确的行数可能会导致非常不同的执行路径,我想…很好,因此显然有很大的改进空间。当你说“确保每个字段……在两个表上都有一个索引”时,你所说的索引到底是什么意思?就我所知有限,索引是添加到列而不是表中的内容。@Jason-它位于列上。我将编辑答案以了解详细信息。这里有一个猜测:我是否会添加一个索引,例如,
customer.id
account.customer\u id
?然后在任何地方都应用同样的想法?太好了。非常感谢你。为了确保我在进行所有这些更改之前都做得正确,我想我应该使用btree
在客户(id)上创建索引index\u customer\u id,并使用btree
在客户(id)上创建索引index\u account\u customer\u id。这个主意对吗?谢谢你这么做。有一件事我很困惑:如果我试图运行查询,它会抱怨“ai”不是唯一的别名,这是真的,因为你有两次
加入帐户\u导入ai
,但我不知道该怎么办。@Jason Swett,修订版,我拿出了第二个实例。。。它是从我反转主查询元素时复制的。。。试试这个。
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