1

我正在构建一个大型数据库。我的一张桌子有30万张唱片,另一张有500万张唱片。 我目前拥有所有外键和名为“ph.trigger_on”的列索引。为大型查询优化MySql数据库

我的问题是我如何优化我的表/查询以获得更快的结果?我试图用这段代码创建一个视图,然后从这个视图中,我可以获得当我对这个视图执行查询时所需要的所有信息。

通过查询仍然很慢,我很难理解EXPLAIN显示的结果。 这是我当前的查询

EXPLAIN SELECT 
ac.account_name AS accountName, 
tm.name AS teamName, 
cp.name AS campaignName, 
cc.call_code_name AS callCode, 
rc.result_code_name AS resultCode, 
zn.name AS zoneName, 
ind.name AS industry, 
(su.first_name + su.middle_name + su.last_name) AS owner_name, 
su.login_user AS ownerLoginUser, 
(su1.first_name + su1.middle_name + su1.last_name) AS firstAttemptBy, 
(su2.first_name + su2.middle_name + su2.last_name) AS lastAttemptBy, 
(su3.first_name + su3.middle_name + su.last_name) AS modifiedBy, 
ci.name AS clientName, 
ph.trigger_on AS triggerOn, 
ph.created_on AS createdOn, 
ph.first_attempt_on AS firstAttemptOn, 
ph.call_subject AS callSubject, 
ph.status, 
ph.last_attempt_on AS lastAttemptOn, 
ph.total_attempts AS totalAttempts, 
ph.call_direction AS callDirection, 
ph.call_notes AS callNotes, 
ph.call_duration AS callDuration, 
ph.modified_on AS modifiedOn 

FROM phone_calls AS ph 
INNER JOIN accounts AS ac ON ph.account_id = ac.account_id 
INNER JOIN clients AS ci ON ac.client_id = ci.client_id 
INNER JOIN industries AS ind ON ac.industry_id = ind.industry_id 
INNER JOIN call_codes AS cc ON ph.call_code_id = cc.call_code_id 
INNER JOIN time_zones AS zn ON ph.time_zone_id = zn.time_zone_id 
INNER JOIN users AS su ON ph.owner_id = su.user_id 

LEFT JOIN teams AS tm ON ph.team_id = tm.team_id 
LEFT JOIN result_codes AS rc ON ph.result_code_id = rc.result_code_id 
LEFT JOIN campaigns AS cp ON ph.campaign_id = cp.campaign_id 
LEFT JOIN users AS su1 ON ph.first_attempt_by = su1.user_id 
LEFT JOIN users AS su2 ON ph.last_attempt_by = su2.user_id 
LEFT JOIN users AS su3 ON ph.modified_by = su3.user_id 
WHERE ph.trigger_on < now() 
LIMIT 1000 

这是我当前的输出。

id select_type table type possible_keys key key_len ref rows Extra 
1 SIMPLE ci ALL PRIMARY    1 
1 SIMPLE zn ALL PRIMARY    1 Using join buffer (Block Nested Loop) 
1 SIMPLE su ALL PRIMARY    1 Using join buffer (Block Nested Loop) 
1 SIMPLE ac ref PRIMARY,client_id,industry_id client_id 4 rdi_cms.ci.client_id 95917 
1 SIMPLE ind eq_ref PRIMARY PRIMARY 4 rdi_cms.ac.industry_id 1 
1 SIMPLE ph ref owner_id,call_code_id,account_id,time_zone_id,trigger_on account_id 4 rdi_cms.ac.account_id 11 Using where 
1 SIMPLE tm ALL PRIMARY    1 Using where; Using join buffer (Block Nested Loop) 
1 SIMPLE rc eq_ref PRIMARY PRIMARY 4 rdi_cms.ph.result_code_id 1 
1 SIMPLE cc eq_ref PRIMARY PRIMARY 4 rdi_cms.ph.call_code_id 1 
1 SIMPLE cp ALL PRIMARY    1 Using where; Using join buffer (Block Nested Loop) 
1 SIMPLE su1 ALL PRIMARY    1 Using where; Using join buffer (Block Nested Loop) 
1 SIMPLE su2 ALL PRIMARY    1 Using where; Using join buffer (Block Nested Loop) 
1 SIMPLE su3 ALL PRIMARY    1 Using where; Using join buffer (Block Nested Loop) 

我该怎么做才能改善我的表格或我的查询。

+0

最重要的是确保所有条件字段都被索引:所有JOIN ON字段和所有WHERE字段。我不认为加入13(!!)桌时你可以做的其他事情......你真的需要12个连接吗?如果某个部分只是为了限制结果,您可以在单独的查询中尝试。 **有时**如果您创建了几个较小的查询,则速度更快(查询缓存!)。 – Rudie 2013-03-18 20:55:29

+0

视图不应该加快速度!您可以尝试通过减少连接数来降低复杂性。您也可以尝试将此查询拆分为多个后续查询,并使用您选择的语言。你也可以尝试移动一些连接到subquerys。如果优化器设法在交叉产品之后执行这些子查询,那么您也会赢得一些时间。 – ITroubs 2013-03-18 20:56:25

+0

我知道意见并不会加速任何事情,但它会使写脚本变得更容易,而不是每次我只需要调用视图就做5次连接。但是我从响应中得到的是避免创建一个大视图,但是每次在我的PHP脚本中创建一个大的查询,这样我也可以加入所需的信息。 – Jaylen 2013-03-18 21:03:28

回答

2

它可以有所作为,如果你把一个连接成一个子查询中查询的这样的SELECT部分​​:

SELECT 
ac.account_name AS accountName, 
tm.name AS teamName, 
cp.name AS campaignName, 
cc.call_code_name AS callCode, 
rc.result_code_name AS resultCode, 
(SELECT zn.name FROM time_zones AS zn WHERE ph.time_zone_id = zn.time_zone_id) AS zoneName, 
(SELECT ind.name FROM industries AS ind WHERE ac.industry_id = ind.industry_id) AS industry, 
(SELECT su.first_name + su.middle_name + su.last_name users AS su WHERE ph.owner_id = su.user_id) AS owner_name, 
su.login_user AS ownerLoginUser, 
(su1.first_name + su1.middle_name + su1.last_name) AS firstAttemptBy, 
(su2.first_name + su2.middle_name + su2.last_name) AS lastAttemptBy, 
(su3.first_name + su3.middle_name + su.last_name) AS modifiedBy, 
ci.name AS clientName, 
ph.trigger_on AS triggerOn, 
ph.created_on AS createdOn, 
ph.first_attempt_on AS firstAttemptOn, 
ph.call_subject AS callSubject, 
ph.status, 
ph.last_attempt_on AS lastAttemptOn, 
ph.total_attempts AS totalAttempts, 
ph.call_direction AS callDirection, 
ph.call_notes AS callNotes, 
ph.call_duration AS callDuration, 
ph.modified_on AS modifiedOn 

FROM phone_calls AS ph 
INNER JOIN accounts AS ac ON ph.account_id = ac.account_id 
INNER JOIN clients AS ci ON ac.client_id = ci.client_id 
INNER JOIN call_codes AS cc ON ph.call_code_id = cc.call_code_id 
INNER JOIN time_zones AS zn ON ph.time_zone_id = zn.time_zone_id 

LEFT JOIN teams AS tm ON ph.team_id = tm.team_id 
LEFT JOIN result_codes AS rc ON ph.result_code_id = rc.result_code_id 
LEFT JOIN campaigns AS cp ON ph.campaign_id = cp.campaign_id 
LEFT JOIN users AS su1 ON ph.first_attempt_by = su1.user_id 
LEFT JOIN users AS su2 ON ph.last_attempt_by = su2.user_id 
LEFT JOIN users AS su3 ON ph.modified_by = su3.user_id 
WHERE ph.trigger_on < now() 
LIMIT 1000 

在这里,我推3加入到你的SELECT部分​​。

+0

因为过滤器不需要这些连接?这是有点聪明... – Rudie 2013-03-18 21:03:43

+0

我看不到你对我的查询做了什么,除去了我需要的2个连接。 – Jaylen 2013-03-18 21:09:13

+0

我没有删除它们!我只是将它们移到稍后的执行状态 – ITroubs 2013-03-18 21:10:35