2013-10-09 152 views
2

我有以下代码,并且在表tblfollowers中只有几个follower_idusername时加载正常。
但是一旦进入数千人,它的载入真的很慢。
有没有更好的方法来写这个?SQL缓慢加载时间

我在它加入的字段上添加了索引,这似乎没有什么区别。

$scheduler->render_table("events 
    LEFT JOIN tblfollowers ON events.id_user = tblfollowers.username 
    WHERE events.status ='active' 
     AND((tblfollowers.follower_id)='$test') OR ((events.id_user) ='$test') 
    GROUP BY events.event_id, events.event_name, events.user_name, events.id_user, events.time, events.details, events.location, events.dresscode 
    ORDER BY events.timestamp DESC" 
    ,"event_id","start_date, start_date,event_name,details"); 
$scheduler->render_sql("SELECT event_id, start_date, end_date, event_name, details 
         FROM events "); 

下面是这个查询的解释:

 
1 SIMPLE events ALL NULL NULL NULL NULL 1593 Using where; Using temporary; Using filesort  
1 SIMPLE tblfollowers ref PRIMARY PRIMARY 
4 dbhappps.events.id_user 17 Using where; Using index  

下面是表

块引用

表活动:

event_id int(11) Primary Unique Index  
event_name varchar(400) 
user_name varchar(155) 
id_user int(11) Primary Unique Index 
start_date datetime 
end_date datetime 
details varchar(700) 
location varchar(255) 
dresscode varchar(255) 
timestamp timestamp on update CURRENT_TIMESTAMP 

块引用

tblfollowers:

username int(11) primary 
follower_id int(11) primary 
timestamp timestamp on update CURRENT_TIMESTAMP 

如何加快这个查询呢?

+0

你能更好地解释你的表模式。具体来说,提供有关您的索引的信息 –

+0

@MikeBrant表中没有索引。有一次,我在id_user和event_id上有一个索引,但正如你在下面看到的那样,答案是索引会减慢上传时间。如果你看看我做的最底部,并在查询中进行EXPLAIN SELECT,那么你可以看到那个结果 – Steven

+0

没有你的索引,你正在做全表扫描。是索引会增加加载时间,但这是你付出的代价。另请看“(tblfollowers.follower_id)='$ test')或((events.id_user)='$ test')”。将id_user检查移到where子句可能不是更好吗? – crafter

回答

1

完全透露:我不知道PHP。

但是,尝试拆分查询并使用UNION将它重新组合在一起。我认为这是通过阻止使用你的索引来杀死你的表现的OR。这是我认为你的查询看起来像PHP之外的东西。

SELECT event_id 
    , start_date 
    , end_date 
    , event_name 
    , details 
    FROM events 
    LEFT JOIN tblfollowers 
    ON events.id_user = tblfollowers.username 
WHERE events.status ='active' 
    AND tblfollowers.follower_id = '$test' 
UNION 
SELECT event_id 
    , start_date 
    , end_date 
    , event_name 
    , details 
    FROM events 
WHERE id_user = '$test' 
+0

哇!这绝对解决了这个问题。现在我必须弄清楚如何将你所做的事情整合到PHP文件中。从10秒到0.0283秒。感谢一堆! – Steven

2

你只需要两个字段在group by(如果电场event_id是主键,你只需要场。
有GROUP BY考虑较少字段应该让你的查询速度更快。
你应该只有把功能独立的领域在group by,列出功能相关的领域有非荒谬和浪费时间。
幸运的MySQL不要求你做到这一点。

$scheduler->render_table("events 
    LEFT JOIN tblfollowers ON events.id_user = tblfollowers.username 
    WHERE events.status ='active' 
    AND '$test' IN (tblfollowers.follower_id, events.id_user) <<-- maybe faster 
    GROUP BY events.event_id, events.id_user <<-- only include unique key fields 
    ORDER BY events.timestamp DESC" 
,"event_id","start_date, start_date,event_name,details"); 
$scheduler->render_sql("SELECT event_id, start_date, end_date, event_name, details 
         FROM events "); 

这里看到更多的信息:http://rpbouman.blogspot.com/2007/05/debunking-group-by-myths.html

为什么慢?
没有tblfollowers和events的表定义很难说。

使用说明
如果你想看看那里的瓶颈,把一个EXPLAIN在选择前,贴在你的问题的结果。

$scheduler->render_sql("EXPLAIN SELECT event_id, start_date, end_date, event_name, details 
         FROM events "); 

后跟踪指标并不能帮助
使用输出explain告知你的决定,增加索引减慢你的插入和更新,以及腌您的磁盘使用情况。

+0

这两个表在事件中都有int(11)用于username,follower_id和id_user。查询仍然运行缓慢,所以我不知道除了卷之外的交易。但是这个数量并不是很大,我预计这个延迟。 – Steven

+0

听起来像硬盘失败。一个破损的扇区可以减慢查询速度,从小秒到小时。尝试将设置移到另一台计算机或硬盘上。 – Johan

+0

并说明了这一点。停止幻想这个问题并开始测量。 – Johan

1

这主要是一个会减慢查询速度的临时文件。 EXPLAIN中的temporary这个词意味着每次运行此查询时,MySQL服务器都必须创建一个临时表。虽然它很小,但它保存在内存中,因此速度相对较快。当它变得足够大时,它将移动到磁盘并使查询运行速度非常慢。

何时使用临时表?它在MySQL Reference Manual – Optimizing Database Structure中有很好的描述。在你的情况下,它必须发生,因为你按timestamp字段排序,GROUP BY子句中没有包含该字段。

接下来,你是否真的需要通过所有这些字段进行分组?由于您正在按events表的主键进行分组,所以将另一个event的字段分组是没有意义的。尝试执行此查询:

$scheduler->render_table("events 
    LEFT JOIN tblfollowers ON events.id_user = tblfollowers.username 
    WHERE events.status = 'active' 
    AND tblfollowers.follower_id = '$test' 
    OR events.id_user = '$test' 
    GROUP BY events.event_id, events.timestamp 
    ORDER BY events.timestamp DESC" 
, "event_id", "start_date, start_date, event_name, details"); 

编辑:顺便说一句,你没忘了把周围的状况的括号? AND优先于OR

WHERE events.status ='active' 
     AND (tblfollowers.follower_id='$test' OR events.id_user='$test') 

这样对我来说似乎更符合逻辑。

+0

好吧,这似乎没有任何工作,所以也许我可以解释我正在试图完成查询。这些问题始于我向1500名追随者添加了1500名追随者。我正在尝试获取由id_user 50发布的所有事件以及tblfollowers中follower_id 50所发生的任何事件。 – Steven

+0

它在我的原始示例中的括号中。 – Steven

+0

尝试在'timestamp'字段中添加'INDEX' - 必须避免临时表。顺便说一句,查询运行了多久?1593x17行不能太多,即使对于磁盘上的文件... – Dmitry

0

很难说没有创建表语句。

对于该组和按顺序。 如果event_id不是主节点,则可以通过在event_id,timestamp desc上添加复合索引来看到一些改进。如果按event_id排序,可以接受timestamp desc,这会为您节省一些时间。通过这种重新排序,组会进行隐式排序,从而减慢速度。按event_id分组,时间戳ASC然后通过时间戳DESC进行排序可能会遇到该排序的最差情况。

如果event_id是主要的,则在时间戳DESC上添加索引将创建event_id和timstamp DESC的组合索引。