如何让这个查询更快地运行......?
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查询结果:
我没有设置任何外键......我试图避免对数据库进行更改,因为必须尽快进行全面检修。
只有主键是每个表的id,例如account_id,ftp_id,ppc_id ......
答案 0 :(得分:4)
索引
您需要 - 至少 - JOIN
条件中使用的每个字段的索引。
WHERE
或GROUP BY
或ORDER BY
条款中显示的字段的索引大部分时间都是有用的。
在表中,在JOIns(或WHERE或GROUP BY或ORDER BY)中使用两个或多个字段时,这些(两个或更多)字段的复合(组合)索引可能比单独的索引更好。例如,在SiteNumbers
表中,可能的索引是复合(number_accountid, number_active)
或(number_active, number_accountid)
。
布尔字段(ON / OFF,活动/非活动)中的条件有时会减慢查询速度(因为索引不是选择性的,因此不是很有帮助)。在这种情况下,重组(父规范化)表是一种选择,但可能你可以避免增加的复杂性。
除了通常的建议(检查EXPLAIN计划,在需要时添加索引,测试查询的变体),
我注意到在您的查询中有一个部分笛卡尔积。表Accounts
与三个表FTPDetails
,SiteNumbers
和PPC
之间存在一对多关系。这样做的结果是,如果您有例如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