How to speed up this mySQL query (filesort issue)? - php

I have following MYSQL query:
select IF(`User`='101',`Friend`,`User`) as `Kto`,`Recent`
from `friends`
WHERE (`User`='101' || `Friend`='101') AND `Status`=1
HAVING `Kto` IN (SELECT `Id` FROM `users` WHERE `Id`=`Kto` AND `Online`>='100')
ORDER by Recent DESC limit 11
Using ORDER by Recent DESC query takes longer (Showing rows 0 - 10 (11 total, Query took 0.0090 sec) [Recent: 9337663 - 7683644])
If I do not use Order by, it is too mutch faster (Showing rows 0 - 10 (11 total, Query took 0.0005 sec))
In explain query with ORDER by shows filesort, which i guess is the slowness problem, see below:
Could you please help me, how to get rid of this filesort, or how to optimize this query, or help me to add proper index just for this query?

You can try this, mate:
SELECT
IF(f.`User`='101',f.`Friend`,f.`User`) as `Kto`,
f.`Recent`
FROM
`friends` f
INNER JOIN `users` u ON u.`Id` IN (f.`User`, f.`Friend`)
WHERE
(f.`User` = '101' || f.`Friend` = '101')
AND f.`Status` = 1
AND u.`Online` >= '100'
ORDER BY
f.Recent DESC
LIMIT 11;

Related

MySQL time out issue

I am facing serious issue in my workout related to PHP and MySql on Linux server while when am running same code with same database in localhost, it's working fine.
As well as I have almost 30,000 records in database table and mysql is:
SELECT * FROM tbl_movies where id not in (select movie_id from tbl_usermovieque where user_id='3' union
select movie_id from tbl_user_movie_response where user_id='3' union
select movie_id from tbl_user_movie_fav where user_id='3') and id < 220 order by rand() limit 0,20
its taking 0.0010 sec in my localhost and INFINITE on our linux server. i unable to find the reason.
Thanks
Kamal
Can you confirm this return the same result ? It should be faster this way. Union are usefull sometime but not really optimized.
SELECT * FROM tbl_movies where id not in (
select distinct movie_id
from tbl_movies m
inner join tbl_usermovieque um ON um.movie_id = m.movie_id = m.movie_id
inner join tbl_user_movie_response umr ON umr.movie_id = m.movie_id = m.movie_id
inner join tbl_user_movie_fav umf ON umf.movie_id = m.movie_id = m.movie_id
where um.user_id = 3 or umr.user_id = 3 or umf.user_id = 3
) and id < 220 order by rand() limit 0,20;
PS : I assume you have Index un oser_id and id_movie
EDIT : your problem may come from rand()
MySQL order by optimization Look for RAND() in the page : in comment there are some performance test => rand() alone seams to be a bad solution
Performance
Now let's see what happends to our performance. We have 3 different
queries for solving our problems.
Q1. ORDER BY RAND()
Q2. RAND() * MAX(ID)
Q3. RAND() * MAX(ID) + ORDER BY ID
Q1 is expected to cost N * log2(N), Q2 and Q3 are nearly constant.
The get real values we filled the table with N rows ( one thousand to
one million) and executed each query 1000 times.
Rows ||100 ||1.000 ||10.000 ||100.000 ||1.000.000
Q1||0:00.718s||0:02.092s||0:18.684s||2:59.081s||58:20.000s
Q2||0:00.519s||0:00.607s||0:00.614s||0:00.628s||0:00.637s
Q3||0:00.570s||0:00.607s||0:00.614s|0:00.628s ||0:00.637s
As you can see the plain ORDER BY RAND() is already behind the
optimized query at only 100 rows in the table.

How to perform multiple table operations in mysql?

I just want to perform multiple table operations in single query. The query is:
select name,sno , id as ids ,(select sum(amount) from client_credits
where user_id = ids) As total from clients where sno = '4' and total > '0'
This query is not working when I am trying use ** total > 0 **. Is there any other possibility ways? Please help me.
total is an alias. Aliases are not resolved when the WHERE clause is reached.
Try: where sno = 4 having total > 0
Alternatively, and more efficiently:
SELECT `c`.`name`, `c`.`sno`, `c`.`id`, SUM(`ccr`.`amount`) AS `total`
FROM `clients` AS `c`
JOIN `client_credits` AS `ccr` ON `c`.`id`=`ccr`.`user_id`
WHERE `c`.`sno` = 4
GROUP BY `c`.`id`
Notice how the total > 0 part is gone? That's because if there are no rows to join, then nothing will be joined and the rows are removed from the result ;)

Can I Count How Many Results Come From Each MySQL Select / Union

I have a query that follows this format:
(SELECT t.column1, t.column2
FROM table t
WHERE t.status = 1
LIMIT 10)
UNION
(SELECT t.column1, t.column2
FROM table t
WHERE t.status = 2
LIMIT 10)
The end result is that I need to have 20 rows. If the first SELECT statement can only find 9 rows with t.status = 1, then I would like the second SELECT statement to use LIMIT 11 instead of LIMIT 10
I am using PHP to write and run the query, but I am looking for something that will execute within MySQL so I can run it all as one query.
Any ideas would be greatly appreciated.
Add one more limit 'outside' with the total count and use the same for the limit of the 2-nd query.
(
SELECT t.column1, t.column2
FROM table t
WHERE t.status = 1
LIMIT 10 # 1/2 of total rows
)
UNION
(
SELECT t.column1, t.column2
FROM table t
WHERE t.status = 2
LIMIT 20 # total rows
)
LIMIT 20 # total rows

Efficiency of queries against DATABASE Issue

I`m trying to query my database with 4 queries, each query will give me the number of rows that I need but I faced with but I notice when I do the query on the server that strong, everything works fast (relatively), but if I make it a relatively simple server that I deserve the maximum working time (30 seconds, the limit execution time(PHP)).
my while loop works with list of MokedCcode each MokedCcode goes into the queries and go to the next MokedCcode.
Notes :
1) I know it will be proportional to the number of MokedCcode-s.
2) I need to increase the execution time limit?
1) there is more efficient way to make those queries? maybe I dont use the mysql features right.
for example the first query called $emerg, this query need to give me the number of rows between dates, where WCODE have priority 1 and it has to be match of MokedCcode on both tables ( t and e ).
$emerg = mysql_num_rows(mysql_query("SELECT t.*,e.DISCODE,e.AREA,e.COLOR,e.PRIORITY FROM $tbl_name AS t
LEFT JOIN eventcodes AS e ON t.MokedCcode = e.MokedCcode AND t.WCODE=e.WCODE
WHERE (t.MokedCcode='$MokedCcode' ) AND e.PRIORITY='1'
AND t.ndate BETWEEN '$start' AND '$end' ORDER By `id` DESC "));
In addition I added the 3 more queries, I would like to get some advice how to make it faster Or I dont have any choice and keep it like that.
The 3 other queries:
$regular = mysql_num_rows(mysql_query("SELECT t.*,e.DISCODE,e.AREA,e.COLOR,e.PRIORITY FROM $tbl_name AS t
LEFT JOIN eventcodes AS e ON t.MokedCcode = e.MokedCcode AND t.WCODE=e.WCODE
WHERE (t.MokedCcode='$MokedCcode' ) AND e.PRIORITY!='1'
AND t.ndate BETWEEN '$start' AND '$end' ORDER By `id` DESC "));
$regHandled = mysql_num_rows(mysql_query("SELECT t.*,e.DISCODE,e.AREA,e.COLOR,e.PRIORITY FROM $tbl_name AS t
LEFT JOIN eventcodes AS e ON t.MokedCcode = e.MokedCcode AND t.WCODE=e.WCODE
WHERE (t.MokedCcode='$MokedCcode' ) AND e.PRIORITY!='1'
AND t.EventHandling!='0' AND t.ndate BETWEEN '$start' AND '$end' ORDER By `id` DESC "));
$emergHandled = mysql_num_rows(mysql_query("SELECT t.*,e.DISCODE,e.AREA,e.COLOR,e.PRIORITY FROM $tbl_name AS t
LEFT JOIN eventcodes AS e ON t.MokedCcode = e.MokedCcode AND t.WCODE=e.WCODE
WHERE (t.MokedCcode='$MokedCcode' ) AND e.PRIORITY='1'
AND t.EventHandling!='0' AND t.ndate BETWEEN '$start' AND '$end' ORDER By `id` DESC "));
I didn't exactly understand what you are trying to achieve.
If you just want the count Why are you selecting all the rows? cant you use COUNT() MySQL function? It is always slow to get all the data to your script and then count the rows.
Even if you want to select all those columns, try using t.field1, t.field2, ... instead of t.*

getting non-distinct results from a distinct mysql query

Right, another question on queries (there must be a syntax guide more helpful than mySQL's manual, surely?)
I have this query (from another helpful answer on SO)...
SELECT DATE_FORMAT(`when`, '%e_%c_%Y')date, COUNT(`ip`) AddressCount FROM `Metrics` WHERE `ID` = '1' GROUP BY DATE(`when`)
I now want to do a similar query to get unique/distinct results for the IPs... i.e. unique visitors per date. My query was this...
SELECT DATE_FORMAT(`when`, '%e_%c_%Y')date, COUNT(distinct `ip`) AddressCount FROM `Metrics` WHERE `ID` = '1' GROUP BY DATE(`when`)
However, that returns a repetition of dates, though different quantities of Addresscount...
date AddressCount
29_6_2009 1
30_6_2009 1
29_6_2009 1
30_6_2009 1
29_6_2009 1
NULL 1
15_5_2009 1
14_5_2009 2
NULL 3
14_5_2009 4
15_5_2009 1
26_6_2009 1
29_6_2009 1
26_6_2009 1
15_5_2009 1
26_6_2009 1
29_6_2009 1
Any ideas on where I'm going wrong?
Your group by will need to match the data you're selecting, so this should work:
SELECT DATE_FORMAT(`when`, '%e_%c_%Y')date, COUNT(distinct `ip`) AddressCount FROM `Metrics` WHERE `ID` = '1' GROUP BY date
Try
SELECT DATE_FORMAT(when, '%e_%c_%Y')date, COUNT(distinct ip) AddressCount FROM Metrics WHERE ID = '1' GROUP BY date(when)
You might have run into some bugs when using reserved words in MySQL

Categories