简体   繁体   中英

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

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

********EDIT*********

I was asked to run the query with an EXPLAIN the result is below

从查询中解释结果

********EDIT********** View Definitition

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_Post.post_user_id
  • PAS_Post.post_type
  • PAS_Post.post_updated
  • PAS_Follow.folw_followed_user_id
  • PAS_Follow.folw_deleted
  • 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.


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

Why i am referring you to use 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 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.

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.

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

Optimize Mysql Union

MySQL Performance Blog

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.

Bye, Gnagno

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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