MySQL Query Optimization - Sub Queries + Multiple Joins - php

How can I optimize this query? It takes 2-3 seconds to get 10 rows.
SELECT users.user_id, users.user_name, users.user_display_name,
(SELECT COUNT(tweet_id) FROM tweets WHERE tweet_user_id = users.user_id AND tweet_status = 1) AS user_tweets_count,
(SELECT COUNT(tweet_reply_id) FROM tweets_reply tr JOIN tweets t ON t.tweet_id = tr.tweet_reply_tweet_id WHERE tweet_reply_user_id = users.user_id AND t.tweet_status = 1 AND tr.tweet_reply_status = 1) AS user_replies_count
FROM users
JOIN tweets ON tweets.tweet_user_id = users.user_id
JOIN tweets_reply ON tweets_reply.tweet_reply_user_id = users.user_id
WHERE (tweets_reply.tweet_reply_status = 1 AND tweets.tweet_status = 1)
GROUP BY users.user_id
ORDER BY (user_tweets_count + user_replies_count) DESC
LIMIT 10

SELECT users.user_id, users.user_name, users.user_display_name,
COUNT(tweets.tweet_id) AS user_tweets_count,
COUNT(tweets_reply.tweet_reply_id) AS user_replies_count
FROM users
JOIN tweets ON tweets.tweet_user_id = users.user_id
JOIN tweets_reply ON tweets_reply.tweet_reply_user_id = users.user_id
WHERE (tweets_reply.tweet_reply_status = 1 AND tweets.tweet_status = 1)
GROUP BY users.user_id
ORDER BY (user_tweets_count + user_replies_count) DESC
LIMIT 10
Hope this helps.

Related

single mysql query for choosing 25 records (9+16) using union all and based on 2 different conditions

I need to fetch 25 records using mysql out of which first 9 must be based on the descending order of likes count (chosen randomly) from 200 top appreciated and balance 16 randomly from the remaining items (excluding 9, that are already filtered). Is it possible to do this using a single mysql query? Any help will be appreciated.
Here is my query...
(SELECT * FROM (SELECT tiles.,users.first_name,users.last_name, users.mosaicname,users.country,users.city,users.state,users.profile_image,COUNT(tile_appreciations.tile_id) AS appreciation_count FROM tiles LEFT JOIN tile_appreciations ON tile_appreciations.tile_id = tiles.id INNER JOIN users ON users.id = tiles.user_id LEFT JOIN user_settings ON user_settings.user_id = tiles.user_id WHERE tiles.view_mode = 'PB' AND users.status = 'Y' AND tiles.moved_stat = '1' AND user_settings.public_profile = 'Y' GROUP BY tiles.id ORDER BY appreciation_count DESC LIMIT 200) as t1 ORDER BY RAND() LIMIT 9) UNION ALL (SELECT tiles.,users.first_name,users.last_name,users.mosaicname,users.country,users.city,users.state,users.profile_image,COUNT(tile_appreciations.tile_id) AS appreciation_count FROM tiles LEFT JOIN tile_appreciations ON tile_appreciations.tile_id = tiles.id INNER JOIN users ON users.id = tiles.user_id LEFT JOIN user_settings ON user_settings.user_id = tiles.user_id WHERE tiles.view_mode = 'PB' AND users.status = 'Y' AND tiles.moved_stat = '1' AND user_settings.public_profile = 'Y' GROUP BY tiles.id ORDER BY RAND() LIMIT 16)
I don't know if using UNION ALL is a hard requirement, but SQL already has a very good system for filtering out results from the first query in the second query: it is called UNION. You can choose the remaining 16 by taking the union of 9 of the best 200 and 25 of the whole set and then limiting the total result to 25. I'm assuming here that UNION will remove duplicates from the second set and not the first.
Try something like this:
SELECT * FROM (
SELECT * FROM (
SELECT tiles.*,users.first_name,users.last_name, users.mosaicname,users.country,users.city,users.state,users.profile_image,COUNT(tile_appreciations.tile_id) AS appreciation_count
FROM tiles LEFT JOIN tile_appreciations ON tile_appreciations.tile_id = tiles.id INNER JOIN users ON users.id = tiles.user_id LEFT JOIN user_settings ON user_settings.user_id = tiles.user_id
WHERE tiles.view_mode = 'PB' AND users.status = 'Y' AND tiles.moved_stat = '1' AND user_settings.public_profile = 'Y'
GROUP BY tiles.id
ORDER BY appreciation_count DESC LIMIT 200
) as best200
ORDER BY RAND()
LIMIT 9
) UNION (
SELECT tiles.*,users.first_name,users.last_name,users.mosaicname,users.country,users.city,users.state,users.profile_image,COUNT(tile_appreciations.tile_id) AS appreciation_count
FROM tiles LEFT JOIN tile_appreciations ON tile_appreciations.tile_id = tiles.id INNER JOIN users ON users.id = tiles.user_id LEFT JOIN user_settings ON user_settings.user_id = tiles.user_id
WHERE tiles.view_mode = 'PB' AND users.status = 'Y' AND tiles.moved_stat = '1' AND user_settings.public_profile = 'Y'
GROUP BY tiles.id
ORDER BY RAND()
LIMIT 25
)
LIMIT 25;

Combine MySQL query with a row count query for optimization with PHP

I have a working PHP script that selects the content with a join of a user table. Then I while loop the results.
However, I was wondering if it would be possible to instead of calling another query each loop, call it in the initial query? Basically merging them?
Code:
$content_result = mysql_query("
SELECT content.id, content.type, content.title, content.url, users.username
FROM content
INNER JOIN users ON content.uploaderuid = users.id
ORDER BY content.id DESC
LIMIT $offset, $rowsperpage
");
while($content_row = mysql_fetch_array($content_result)){
$contentid = $content_row['id'];
$result_num_votes = mysql_fetch_assoc(mysql_query("SELECT COUNT(*) FROM votes WHERE votedcontentid = '$contentid' AND value = '1'"));
$num_votes = $result_num_votes['COUNT(*)'];
}
Try this:
SELECT COUNT(votedcontentid)as numbervotes,content.id, content.type, content.title, content.url, users.username
FROM content
INNER JOIN users ON content.uploaderuid = users.id
JOIN votes ON votes.votedcontentid = content.id
ORDER BY content.id DESC LIMIT $offset, $rowsperpage
And here change it to
$num_votes = $result_num_votes['numbervotes'];

How do i sort by users with profile pictures at the top?

So i'm filling in for our developer at the moment (be for-warned i'm a beginner) but I"m trying to simply sort my search results by profiles that have a profile picture included (i.e, i don't want blank profile pictures to show up at the top of the results...they should all be at the end of the results)...Note that there are a couple user types which is why there is so much code...
I'm pretty sure where i'm going wrong is the 2 lines...
ORDER BY $order u.picture ISNULL DESC"; (which relates to ordering by profile pictures). Would really appreciate any and all help...thx!
The code is as follows:
if ($user_type == 1) {
$sql = "SELECT a.*, u.*,
(SELECT COUNT(DISTINCT userId) FROM LF_usertype_A WHERE usertype_BId = u.userId AND status = 1) as i_cnt,
(SELECT COUNT(productId) FROM LF_products WHERE userId = u.userId AND status = 1) as product_cnt,
(SELECT COUNT(transactionId)
FROM LF_Transactions
WHERE usertypeBId = u.userId
AND (status = 1 OR status = 2)
AND type = 9
AND userId != usertypeBId
AND userId != usertypeAId) AS cnt
FROM LF_Users u
JOIN LF_products a ON a.userId = u.userId
LEFT JOIN LF_Transactions t ON t.productId = a.productId
WHERE a.status = 1
AND u.status = 1
AND u.userType = :ut $where
GROUP BY u.userID
ORDER BY $order u.name DESC LIMIT 200";
} elseif ($filter != "recent" && $user_type == 2) {
$sql = "SELECT u.*,
(SELECT COUNT(a.productId) FROM LF_usertypeA a INNER JOIN LF_products ON a.productId = m.productId INNER JOIN LF_Users uu ON uu.userId = a.usertypeAId WHERE a.userId = u.userId AND uu.status = 1 AND a.status = 1 AND m.status = 1) as product_cnt,
(SELECT COUNT(transactionId)
FROM LF_Transactions
WHERE usertypeBId = u.userId
AND (status = 1 OR status = 2)
AND type = 9
AND userId != usertypeAId
AND userId != usertypeBId) AS cnt
FROM LF_Users u
LEFT JOIN LF_Transactions t ON t.usertypeBId = u.userId
WHERE u.status = 1
AND u.userId != 1
AND u.userType = :ut $where
GROUP BY u.userID
ORDER BY $order u.name DESC LIMIT 200
ORDER BY $order u.picture ISNULL DESC";
} else {
$sql = "SELECT u.*,
(SELECT COUNT(a.productId) FROM LF_usertype_A a INNER JOIN LF_products m ON a.productId = m.productId INNER JOIN LF_Users uu ON uu.userId = a.usertypeAId WHERE a.userId = u.userId AND uu.status = 1 AND a.status = 1 AND m.status = 1) as product_cnt,
(SELECT COUNT(transactionId)
FROM LF_Transactions
WHERE usertypeBId = u.userId
AND (status = 1 OR status = 2)
AND type = 9
AND userId != usertypeAId
AND userId != usertypeBId) AS cnt
FROM LF_Users u
WHERE u.status = 1
AND u.userId != 1
AND u.userType = :ut $where
GROUP BY u.userID
ORDER BY $order u.name DESC LIMIT 200
ORDER BY $order u.picture ISNULL DESC";
}
You would have to put the isnull condition before your regular sort order if you want it to take precedence:
ORDER BY ISNULL(u.picture), $order

Why does adding count() to my sql query stop it from working?

Why does this return 23 rows (the right amount):
select users.user_id, users.fname, users.lname,
stars.stars, comments.comment from users
LEFT JOIN stars on users.user_id = stars.userid
JOIN comments on users.user_id = comments.sender
where users.user_id = ? order by comments.time desc;
and this return 1 row?:
select users.user_id, users.fname, users.lname,
stars.stars, count(distinct comments.id) as amount,
comments.comment from users
LEFT JOIN stars on users.user_id = stars.userid
JOIN comments on users.user_id = comments.sender
where users.user_id = ? order by comments.time desc;
Cheers.
you need to group the main data or do a sub-query for the field.

Combine Entry Count in a UNION Query

How do i combine the counts from all the tables being used in a UNION query. This is what i have:
$query = "SELECT COUNT(*) as num
from table_one LEFT JOIN table_constant on table_one.c_id
= table_constant.c_id
where table_constant.user_id = '$uid'
UNION
SELECT COUNT(*) as num
from table_two LEFT JOIN table_constant on table_two.c_id
= table_constant.c_id
where table_two.added_by = '$uid'
UNION
SELECT COUNT(*) as num
from table_three LEFT JOIN table_constant ON table_three.c_id
= table_constant.c_id
where table_constant.user_id = '$uid'
UNION
SELECT COUNT(*) as num
from table_four LEFT JOIN table_constant ON table_four.c_id
= table_constant.c_id
where table_constant.user_id = '$uid'
ORDER BY date_time_added DESC";
$total_pages = mysql_fetch_array(mysql_query($query));
$total_pages = $total_pages[num];
Wrap the whole thing in yet another query and do the summation there.
SELECT sum(num)
FROM ( ... union queries here ...) as subquery;
Or loop over the returned rows in PHP and do the summation yourself.
Did you try to put count outside and apply it on sub query containing all tables union result.
SELECT COUNT(*) FROM (SELECT ...) as abc
Or try this out
Select mytable .userid, sum(mytable .subcount) as totalcount from
(
select userid, count(*) as subcount from table1 group by userid
union all
select userid, count(*) as subcount from table2 group by userid
)
as mytable
group by mytable .userid
or try using FULL OUTER JOIN instead of union it will give you the same result..
SELECT Count(UserID), UserId
FROM MyTable1
GROUP BY MyTable1.UserID
UNION
SELECT Count(UserID), UserId
FROM MyTable2
FULL OUTER JOIN MyTable2 ON (MyTable1.UserId=MyTable2.UserId)
GROUP BY MyTable2.UserID
Updated answer:
IF Your query is working fine follow my first option that i gave means
select count(*) from (your query) as pagecount..
Then your query would be like this.....
select count(*) from
(
SELECT COUNT(*) as num
from table_one LEFT JOIN table_constant on table_one.c_id
= table_constant.c_id
where table_constant.user_id = '$uid'
UNION
SELECT COUNT(*) as num
from table_two LEFT JOIN table_constant on table_two.c_id
= table_constant.c_id
where table_two.added_by = '$uid'
UNION
SELECT COUNT(*) as num
from table_three LEFT JOIN table_constant ON table_three.c_id
= table_constant.c_id
where table_constant.user_id = '$uid'
UNION
SELECT COUNT(*) as num
from table_four LEFT JOIN table_constant ON table_four.c_id
= table_constant.c_id
where table_constant.user_id = '$uid'
ORDER BY date_time_added DESC") as pagecount
There must be a better way to write that :/. A union is very powerful, but you are calling 4 selects in a single query, and if that is run every page, it will really hurt performance.
To answer you question, something like:
SELECT
SUM (mnTbl.num) as sumNum
FROM
(
SELECT
COUNT(*) as num
FROM
table_one
LEFT JOIN
table_constant
ON
table_one.c_id = table_constant.c_id
WHERE
table_constant.user_id = '$uid'
UNION
SELECT
COUNT(*) as num
FROM
table_two
LEFT JOIN
table_constant
ON
table_two.c_id = table_constant.c_id
WHERE
table_two.added_by = '$uid'
UNION
SELECT
COUNT(*) as num
FROM
table_three
LEFT JOIN
table_constant
ON
table_three.c_id = table_constant.c_id
WHERE
table_constant.user_id = '$uid'
UNION
SELECT
COUNT(*) as num
FROM
table_four
LEFT JOIN
table_constant
ON
table_four.c_id = table_constant.c_id
WHERE
table_constant.user_id = '$uid'
) as mnTbl
ORDER BY
date_time_added DESC

Categories