如何让这个查询运行得更快?

时间:2011-06-30 09:17:57

标签: mysql sql performance

如何让这个查询更快地运行......?

SELECT    account_id, 
          account_name, 
          account_update, 
          account_sold, 
          account_mds, 
          ftp_url,         
          ftp_livestatus, 
          number_digits, 
          number_cw,
          client_name, 
          ppc_status, 
          user_name 
FROM     
         Accounts, 
         FTPDetails, 
         SiteNumbers, 
         Clients, 
         PPC, 
         Users 

WHERE    Accounts.account_id = FTPDetails.ftp_accountid 
AND      Accounts.account_id = SiteNumbers.number_accountid 
AND      Accounts.account_client = Clients.client_id     
AND      Accounts.account_id = PPC.ppc_accountid 
AND      Accounts.account_designer = Users.user_id   
AND      Accounts.account_active = 'active' 
AND      FTPDetails.ftp_active = 'active' 
AND      SiteNumbers.number_active = 'active' 
AND      Clients.client_active = 'active'    
AND      PPC.ppc_active = 'active'   
AND      Users.user_active = 'active' 
ORDER BY 
         Accounts.account_update DESC

提前致谢:)

EXPLAIN查询结果:

first part of table

second part of table

我没有设置任何外键......我试图避免对数据库进行更改,因为必须尽快进行全面检修。

只有主键是每个表的id,例如account_id,ftp_id,ppc_id ......

4 个答案:

答案 0 :(得分:4)

索引

  • 您需要 - 至少 - JOIN条件中使用的每个字段的索引。

  • WHEREGROUP BYORDER BY条款中显示的字段的索引大部分时间都是有用的。

  • 在表中,在JOIns(或WHERE或GROUP BY或ORDER BY)中使用两个或多个字段时,这些(两个或更多)字段的复合(组合)索引可能比单独的索引更好。例如,在SiteNumbers表中,可能的索引是复合(number_accountid, number_active)(number_active, number_accountid)

  • 布尔字段(ON / OFF,活动/非活动)中的条件有时会减慢查询速度(因为索引不是选择性的,因此不是很有帮助)。在这种情况下,重组(父规范化)表是一种选择,但可能你可以避免增加的复杂性。


除了通常的建议(检查EXPLAIN计划,在需要时添加索引,测试查询的变体),

我注意到在您的查询中有一个部分笛卡尔积。表Accounts与三个表FTPDetailsSiteNumbersPPC之间存在一对多关系。这样做的结果是,如果您有例如1000个帐户,并且每个帐户与10个FTPDetails,20个SiteNumbers和3个PPC相关,则查询将返回每个帐户600行(10x20x3的乘积)。总计600K行,其中有许多数据重复。

您可以将查询拆分为三加一基础数据(帐户和其余表)。这样,只会传输34K行数据(长度较小):

Accounts JOIN Clients JOIN Users 
  (with all fields needed from these tables)
  1K rows

Accounts JOIN FTPDetails
  (with Accounts.account_id and all fields from FTPDetails)
  10K rows

Accounts JOIN SiteNumbers
  (with Accounts.account_id and all fields from SiteNumbers)
  20K rows

Accounts JOIN PPC
  (with Accounts.account_id and all fields from PPC)
  3K rows

然后使用客户端4个查询中的数据显示组合信息。



我会添加以下索引:

Table Accounts
  index on (account_designer)
  index on (account_client)
  index on (account_active, account_id)
  index on (account_update)

Table FTPDetails
  index on (ftp_active, ftp_accountid)

Table SiteNumbers
  index on (number_active, number_accountid)

Table PPC
  index on (ppc_active, ppc_accountid)

答案 1 :(得分:3)

使用EXPLAIN找出可以使用的索引以及实际使用的索引。如有必要,请创建适当的索引。

如果FTPDetails.ftp_active只有两个有效条目'active''inactive',请使用BOOL作为数据类型。

作为旁注:我强烈建议使用显式连接而不是隐式连接:

SELECT
  account_id, account_name, account_update, account_sold, account_mds, 
  ftp_url, ftp_livestatus, 
  number_digits, number_cw,
  client_name, 
  ppc_status, 
  user_name 
FROM Accounts 
INNER JOIN FTPDetails
  ON  Accounts.account_id = FTPDetails.ftp_accountid
  AND FTPDetails.ftp_active = 'active'
INNER JOIN SiteNumbers
  ON  Accounts.account_id = SiteNumbers.number_accountid 
  AND SiteNumbers.number_active = 'active'
INNER JOIN Clients
  ON  Accounts.account_client = Clients.client_id
  AND Clients.client_active = 'active'
INNER JOIN PPC
  ON  Accounts.account_id = PPC.ppc_accountid
  AND PPC.ppc_active = 'active'
INNER JOIN Users
  ON  Accounts.account_designer = Users.user_id
  AND Users.user_active = 'active'
WHERE Accounts.account_active = 'active' 
ORDER BY Accounts.account_update DESC

这使查询更具可读性,因为连接条件接近正在连接的表的名称。

答案 2 :(得分:0)

EXPLAIN,标记不同的选项。对于初学者,我确信几个查询会比这个怪物更快。首先,因为查询优化器将花费大量时间来检查哪种连接顺序是最好的(5!= 120种可能性)。其次,SELECT ... WHERE ....active = 'active'之类的查询将被缓存(尽管它取决于数据更改量)。

答案 3 :(得分:0)

您的主要问题之一是:x.y_active = 'active'

问题:基数低
活动字段是具有2个可能值的布尔字段,因此它具有非常低的基数。 当30%或更多的行具有相同的值时,MySQL(或任何相关的SQL都不会使用索引) 强制索引是没用的,因为它会使您的查询变慢,而不是更快。

解决方案:对表格进行分区
解决方案是在active列上对表进行分区 这将排除所有非活动字段的考虑因素,并使select行为就像您在xxx-active字段上实际拥有工作索引一样。

<强>旁注
请不要使用隐式where连接,这很容易出错,并且消耗很有用。
请改用Oswald's answer之类的语法。

<强>链接:
基数:http://en.wikipedia.org/wiki/Cardinality_(SQL_statements)
基数和指数:http://www.bennadel.com/blog/1424-Exploring-The-Cardinality-And-Selectivity-Of-SQL-Conditions.htm
MySQL分区:http://dev.mysql.com/doc/refman/5.5/en/partitioning.html