简体   繁体   English

MySQL Select查询执行缓慢

[英]Slow Execution of MySQL Select Query

I have the following query… 我有以下查询...

SELECT DISTINCT * FROM 
vPAS_Posts_Users 
WHERE (post_user_id =:id AND post_type != 4) 
AND post_updated >:updated 
GROUP BY post_post_id 
UNION 
SELECT DISTINCT vPAS_Posts_Users.* FROM PAS_Follow 
JOIN vPAS_Posts_Users ON 
( PAS_Follow.folw_followed_user_id = vPAS_Posts_Users.post_user_id ) 
WHERE (( PAS_Follow.folw_follower_user_id =:id AND PAS_Follow.folw_deleted = 0 ) 
OR ( post_type = 4 AND post_passed_on_by = PAS_Follow.folw_follower_user_id 
AND post_user_id !=:id )) 
AND post_updated >:updated 
GROUP BY post_post_id ORDER BY post_posted_date DESC LIMIT :limit

Where :id = 7 , :updated = 0.0 and :limit=40 for example 例如:id = 7:updated = 0.0:limit=40

My issue is that the query is taking about a minute to return results. 我的问题是查询需要大约一分钟才能返回结果。 Is there anything in this query that I can do to speed up the result? 此查询中有什么我可以做以加快结果的速度吗?

I am using RDS 我正在使用RDS

********EDIT********* ********编辑*********

I was asked to run the query with an EXPLAIN the result is below 我被要求使用EXPLAIN运行查询,结果如下

从查询中解释结果

********EDIT********** View Definitition ******** EDIT **********查看定义

CREATE ALGORITHM=UNDEFINED DEFINER=`MySQLUSer`@`%` SQL SECURITY DEFINER VIEW `vPAS_Posts_Users`
AS SELECT
   `PAS_User`.`user_user_id` AS `user_user_id`,
   `PAS_User`.`user_country` AS `user_country`,
   `PAS_User`.`user_city` AS `user_city`,
   `PAS_User`.`user_company` AS `user_company`,
   `PAS_User`.`user_account_type` AS `user_account_type`,
   `PAS_User`.`user_account_premium` AS `user_account_premium`,
   `PAS_User`.`user_sign_up_date` AS `user_sign_up_date`,
   `PAS_User`.`user_first_name` AS `user_first_name`,
   `PAS_User`.`user_last_name` AS `user_last_name`,
   `PAS_User`.`user_avatar_url` AS `user_avatar_url`,
   `PAS_User`.`user_cover_image_url` AS `user_cover_image_url`,
   `PAS_User`.`user_bio` AS `user_bio`,
   `PAS_User`.`user_telephone` AS `user_telephone`,
   `PAS_User`.`user_dob` AS `user_dob`,
   `PAS_User`.`user_sector` AS `user_sector`,
   `PAS_User`.`user_job_type` AS `user_job_type`,
   `PAS_User`.`user_unique` AS `user_unique`,
   `PAS_User`.`user_deleted` AS `user_deleted`,
   `PAS_User`.`user_updated` AS `user_updated`,
   `PAS_Post`.`post_post_id` AS `post_post_id`,
   `PAS_Post`.`post_language_id` AS `post_language_id`,
   `PAS_Post`.`post_type` AS `post_type`,
   `PAS_Post`.`post_promoted` AS `post_promoted`,
   `PAS_Post`.`post_user_id` AS `post_user_id`,
   `PAS_Post`.`post_posted_date` AS `post_posted_date`,
   `PAS_Post`.`post_latitude` AS `post_latitude`,
   `PAS_Post`.`post_longitude` AS `post_longitude`,
   `PAS_Post`.`post_location_name` AS `post_location_name`,
   `PAS_Post`.`post_text` AS `post_text`,
   `PAS_Post`.`post_media_url` AS `post_media_url`,
   `PAS_Post`.`post_image_height` AS `post_image_height`,
   `PAS_Post`.`post_link` AS `post_link`,
   `PAS_Post`.`post_link_title` AS `post_link_title`,
   `PAS_Post`.`post_unique` AS `post_unique`,
   `PAS_Post`.`post_deleted` AS `post_deleted`,
   `PAS_Post`.`post_updated` AS `post_updated`,
   `PAS_Post`.`post_original_post_id` AS `post_original_post_id`,
   `PAS_Post`.`post_original_type` AS `post_original_type`,
   `PAS_Post`.`post_passed_on_by` AS `post_passed_on_by`,
   `PAS_Post`.`post_passed_on_caption` AS `post_passed_on_caption`,
   `PAS_Post`.`post_passed_on_fullname` AS `post_passed_on_fullname`,
   `PAS_Post`.`post_passed_on_avatar_url` AS `post_passed_on_avatar_url`
FROM (`PAS_User` join `PAS_Post` on((`PAS_User`.`user_user_id` = `PAS_Post`.`post_user_id`)));

try this query: 试试这个查询:

SELECT * 
FROM 
    vPAS_Posts_Users 
WHERE 
    post_user_id =:id 
AND post_type != 4 
AND post_updated > :updated 
UNION 
SELECT u.* 
FROM vPAS_Posts_Users u
        JOIN PAS_Follow f ON f.folw_followed_user_id = u.post_user_id
WHERE 
    u.post_updated > :updated
AND (   (f.folw_follower_user_id = :id AND f.folw_deleted = 0) 
    OR  (u.post_type = 4 AND u.post_passed_on_by = f.folw_follower_user_id AND u.post_user_id != :id)
) 
ORDER BY u.post_posted_date DESC;
LIMIT :limit

Other improvements 其他改进

Indices: Be sure you have indices on the following columns: 索引:确保在以下列上有索引:

  • PAS_User.user_user_id PAS_User.user_user_id
  • PAS_Post.post_user_id PAS_Post.post_user_id
  • PAS_Post.post_type PAS_Post.post_type
  • PAS_Post.post_updated PAS_Post.post_updated
  • PAS_Follow.folw_followed_user_id PAS_Follow.folw_followed_user_id
  • PAS_Follow.folw_deleted PAS_Follow.folw_deleted
  • PAS_Post.post_passed_on_by PAS_Post.post_passed_on_by

After that is done, please 1- check the performance again (SQL_NO_CACHE) and 2- extract another explain plan so we can adjust the query. 完成之后,请1-再次检查性能(SQL_NO_CACHE),然后2提取另一个说明计划,以便我们可以调整查询。


EXPLAIN Results 说明结果

说明结果

Here are the some suggestions for the query and view first of all using the UNION for the two result sets which might makes your query to work slow instead you can use the UNION ALL 以下是有关查询的一些建议,并首先对两个结果集使用UNION进行查看,这可能会使查询工作缓慢,而可以使用UNION ALL

Why i am referring you to use UNION ALL 为什么我要让您使用UNION ALL

Reason is both UNION ALL and UNION use temporary table for result generation.The difference in execution speed comes from the fact UNION requires internal temporary table with index (to skip duplicate rows) while UNION ALL will create table without such index.This explains the slight performance improvement when using UNION ALL . 原因是UNION ALLUNION使用临时表来生成结果。执行速度的差异是因为UNION要求内部临时表带有索引(以跳过重复的行),而UNION ALL将创建不具有此类索引的表。使用UNION ALL时的性能改进。 UNION on its own will remove any duplicate records so no need to use the DISTINCT clause, try to only one GROUP BY of the whole result set by subqueries this will also minimize the execution time rather then grouping results in each subquery. UNION会自行删除所有重复的记录,因此无需使用DISTINCT子句,仅尝试按子查询查询整个结果集中的一个GROUP BY,这也将最小化执行时间,而不是对每个子查询进行结果分组。

Make sure you have added the right indexes on the columns especially the columns used in the WHERE,ORDER BY, GROUP BY , the data types should be appropriate for each column with respect to the nature of data in it like post_posted_date should be datetime,date with an index also. 确保在列上添加了正确的索引,尤其是在WHERE,ORDER BY, GROUP BY中使用的列,相对于其中的数据性质,数据类型应该适合于每个列,例如post_posted_date应该是datetime,date与索引也。

Here is the rough idea for the query 这是查询的基本思路

SELECT q.* FROM (
SELECT * FROM 
vPAS_Posts_Users 
WHERE (post_user_id =:id AND post_type != 4) 
AND post_updated >:updated 

UNION ALL


SELECT vPAS_Posts_Users.* FROM PAS_Follow 
JOIN vPAS_Posts_Users ON 
( PAS_Follow.folw_followed_user_id = vPAS_Posts_Users.post_user_id 
AND vPAS_Posts_Users.post_updated >:updated) 
WHERE (( PAS_Follow.folw_follower_user_id =:id AND PAS_Follow.folw_deleted = 0 ) 
OR ( post_type = 4 AND post_passed_on_by = PAS_Follow.folw_follower_user_id 
AND post_user_id !=:id )) 

) q
GROUP BY q.post_post_id ORDER BY q.post_posted_date DESC LIMIT :limit

References 参考

Difference Between Union vs. Union All – Optimal Performance Comparison Union与Union All之间的差异–最佳性能比较

Optimize Mysql Union 优化Mysql联合

MySQL Performance Blog MySQL性能博客

From your explain I can see that most of your table don't have any key except for the primary one, I would suggest you to add some extra key on the columns you're going to join, for example on: PAS_Follow.folw_followed_user_id and vPAS_Posts_Users.post_user_id, just this will result in a big performance boost. 从您的解释中,我可以看到您的大多数表除了主键外没有其他键,我建议您在要连接的列上添加一些额外的键,例如:PAS_Follow.folw_followed_user_id和vPAS_Posts_Users.post_user_id,仅此将大大提高性能。

Bye, Gnagno 再见Gnagno

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM