Given is mySQL table named "user_posts" with the following relevant fields:
indexed in all three fields
My running slow query is here and also i have created an dbFiddle . Output of Explain is in the dbfiddle:
SELECT
P.user_post_id,
P.user_id_fk,P.post_type,
P.who_can_see_post,
P.post_image_id,P.post_video_id,
U.user_name, U.user_fullname,U.influencer_status
FROM user_posts P FORCE INDEX (ix_user_posts_post_id_post_type)
INNER JOIN users U FORCE INDEX (ix_status_istatus)
ON P.user_id_fk = U.user_id
WHERE
U.user_status='1' AND
U.influencer_status = '1' AND
(P.who_can_see_post IN('everyone','influencer','friends')) AND
(P.post_type IN('image','video'))
AND p.user_post_id > 30
ORDER BY
P.user_post_id
DESC LIMIT 30
The query takes extremely long, around 6-15 seconds. The database is not very busy otherwise and performs well on other queries.
I am obviously wondering why the query is so slow.
Is there a way to tell exactly what is taking mySQL so long? Or is there any change I need to make to make the query run faster?
SQL Server uses nested loop, hash, and merge joins. If a slow-performing query is using one join technique over another, you can try forcing a different join type. For example, if a query is using a hash join, you can force a nested loops join by using the LOOP join hint.
Queries can become slow for various reasons ranging from improper index usage to bugs in the storage engine itself. However, in most cases, queries become slow because developers or MySQL database administrators neglect to monitor them and keep an eye on their performance.
You can view this by Right Clicking on Instance Name in SQL Server Management Studio and selecting “Activity Monitor”. Activity monitor tells you what the current and recent activities are in your SQL Server Instance. The above screenshot displays an overview window for the Activity Monitor.
The definition of your ix_status_istatus
key is preventing it being used to optimise the WHERE
clause, as it includes user_id
which is not used in the WHERE
clause. Redefining the index as
ALTER TABLE `users`
ADD PRIMARY KEY (`user_id`),
ADD KEY ix_status_istatus (user_status, influencer_status);
allows it to be used and should speed up your query, changing the search on users
to use index
instead of temporary and filesort
.
Demo on dbfiddle
Update
Further analysis on dbfiddle suggests that it is also better to remove the FORCE INDEX
from the P
table as it is not necessary (only the PRIMARY
key is required) and changing the JOIN
to a STRAIGHT_JOIN
i.e. write the JOIN
as:
FROM user_posts P
STRAIGHT_JOIN users U FORCE INDEX (ix_status_istatus)
ON P.user_id_fk = U.user_id
I think You should limit result set of joining part using conditions inside ON statement.
It’s like doing filtering during joining instead of joining then filtering.
I’ve checked query plan which shows me full utilization of indexes.
SELECT
P.user_post_id,
P.user_id_fk,P.post_type,
P.who_can_see_post,
P.post_image_id,
P.post_video_id,
U.user_name,
U.user_fullname,
U.influencer_status
FROM user_posts P
INNER JOIN
users U
FORCE INDEX (
users_user_status_index,
users_influencer_status_index
)
ON
U.user_id = P.user_id_fk AND
U.user_status='1' AND
U.influencer_status='1'
WHERE
P.who_can_see_post IN('everyone','influencer','friends') AND
P.post_type IN('image','video') AND
P.user_post_id > 30
ORDER BY
P.user_post_id DESC
LIMIT 30
Indexes that I created:
ALTER TABLE `users`
ADD PRIMARY KEY (`user_id`),
ADD KEY users_user_status_index(user_status),
ADD KEY users_influencer_status_index(influencer_status);
dbfiddle
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With