For some reason, after adding 2 more ORDER BY, my query became very slow. Can someone help me to fix it? I really need to use the following ORDER BY clause:
ORDER BY candidates.user_id DESC, candidates.usr_type ASC, all_users.user_id DESC
The main problem is that you are mixing sort orders, this is very slow in MySQL.
Either ORDER BY everything ASC or DESC, but don't mix them.
One solution is to define an extra copy field for usr_type that runs in the opposite order.
Like this
Example
-------------------------------
id usr_type alt_usr_type
1 1 99
2 2 98
3 1 99
4 5 95
Now you can define the select as
ORDER BY candidates.user_id DESC
, candidates.alt_usr_type DESC
, all_users.user_id DESC
And your query will run much faster.
See: http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html
Make sure you have indexes on all fields you're ordering by.
Related
We're currently dealing with a slow query in an odd situation. The issue comes into play when we LIMIT the results by 1, 2, 3, 4, 5, 6, but it works with any other limits. This issue is also limited to this one specific user. We can't reproduce the slowness/timeouts with any other user.
We can change the ORDER BY to use a different column, and the query works. We can remove the LIMIT 1, and the query works. Once we change the LIMIT to anything between 1-6, it timesout.
We could get away with setting the ORDER BY on a different column, but this may cause reporting issues in the future and doesn't address the 'why' is this happening.
The query:
SELECT
*
FROM
table_name tn
WHERE
tn.user = '123'
ORDER BY
timestamp_col DESC
LIMIT 1
And our data:
user --- timestamp_col ---
123 2005-02-23 02:02:34
123 2005-03-21 00:12:30
123 2006-01-09 14:23:48
123 2006-01-10 15:01:05
123 2006-01-20 13:11:13
123 2006-10-20 20:08:00
123 2006-11-01 18:31:03
123 2006-12-01 09:10:12
Are there special needs when ordering by a timestamp?
Add the composite
INDEX(user, timestamp_col)
That way both the WHERE, the ORDER BY, and the LIMIT are all handled by the index. And it will stop after getting the desired LIMIT.
Any single-column index needs to read lots of rows and/or sort those rows.
How to select via sql command on sphinx first first 20 rows order by title WEIGHT and next 20 order by title ASC ( total 40 results ) on the same sql command but to don't give duplicate title output.
I try this sql command but all title results is order via WEIGHT()
$sql = "SELECT *,MAX(WEIGHT()) AS tpw FROM vids_tab
WHERE MATCH('#title " . mysql_real_escape_string( 'fun | funny | today funny' ) . "')
GROUP 5 BY title ORDER BY tpw DESC, title ASC LIMIT 40 OPTION max_matches=40";
Got to be honest, don't really see this being practical in a single query. Just issue two queries. And then remove any duplicates in the application.
In the second make sure over double the number of results, so even if need to remove 20 as duplicates, will still have 20.
If really do want one command, think going to need a UDF. On particular problem, is will need to know range of weights for the first 20 results (so can create a virtual column to sort by (ie to know if row is in the first 20 results)
... ORDER BY IF(WEIGHT() BETWEEN topweight AND bottomweight, WEIGHT(), 0 ) DESC , title ASC
(that ISN'T a valid sphinxQL command, just demonstrating what would need to emulate) So first 20 would order by weight, non first would get same value, and so then order by title.
SELECT * FROM my_database ORDER BY priority DESC LIMIT 1
my_database:
name | priority
##################
dave | 100
pat | 100
jo | 99
1: What's the deciding factor when there's two possible results and the limit is set to 1?
2: Can you add randomization between the two possible matches? How?
1: What's the deciding factor when there's two possible results and the limit is set to 1?
Unless we specify ordering by a primary key (or a combination of fields to make it completely clear to the DB how to order), we cannot predict which of the two possible results will display. Database engine will determine that.
I tried the query (Example: http://www.sqlfiddle.com/#!9/e2df77/2) SELECT * FROM test ORDER BY priority DESC LIMIT 1 and Pat showed up. Then I tried SELECT * FROM test where priority = 100 ORDER BY priority DESC LIMIT 1 and Dave showed up. Moral: don't count on the results unless you tell the database unambiguously how to order information.
2: Can you add randomization between the two possible matches? How?
You can order your query using RAND().
SELECT * FROM test where priority = 100
ORDER BY priority DESC, RAND() DESC LIMIT 1
A variant of above can be used for randomization. order by rand() or order by field, rand() will work.
Example: http://www.sqlfiddle.com/#!9/e2df77/3
If you want to randomize between the highest priorities, then use:
ORDER BY priority DESC, rand()
LIMIT 1
You will only get 1 result, the other one will be discarded. The one who appear on top will be selected, the rest will be discarded.
Yes you can randomize and still limit to get 1 result but it will throw away the ORDER BY priority DESC part. You only need to make the query into SELECT * FROM my_database
ORDER BY RAND()
LIMIT 1;
i have this table and it can be easily sorted by order by id asc or desc but it will always give same result so there is only possibility of getting two results either by asc or desc here is
tablea
id linkid
5454 766
5453 766
5452 766
5451 766
5450 766
5449 766
5448 765
5447 765
5446 765
5445 765
select * from tablea where linkid='766' order by id desc limit 1
or
select * from tablea where linkid='766' order by id asc limit 1
when i use above query i have only two options either to use asc or desc which can sort linkid 766 only in two ways and i will get output of either id 5454 or 5449 but i want to use any one of the id correspnding to linkid .i want output for linkid 766 like this.the query should give any one value not only first or last value which i am getting by using asc or desc but again i dont want to use rand() as it is dead slow
i can try rand() but it will be dead slow
select * from tablea where linkid='766' order by rand() limit 1
any idea how can be achieved.
If your expected result set from the query is small enough, then you may want to consider using app tier for randomizing your selection. I do not know your database infrastructure or load but general rule of thumb I use is that "App Tier is far more easier to scale then the database tier"!
Having said that, I know there are some situations where you really want to randomize results at the DB tier. We had to do that in couple of instances and in our research, we stumbled upon following which seems to have worked for us. http://www.rndblog.com/how-to-select-random-rows-in-mysql/
It doesn't make sense to repeat everything here, but for the sake of ensuring that if the page at the given link disappears, here is a high level summary. Basically, what this link is discussing is.... instead of using RAND in the order by clause (which can be very expensive)
SELECT col1 FROM tbl ORDER BY RAND() LIMIT 10;
Use it in the WHERE clause:
SELECT col1 FROM tbl WHERE RAND()<=0.0006 limit 100;
Hope this helps you.
Have you try this?
SELECT * FROM table LIMIT 1 ORDER BY id DESC
Or
SELECT * FROM table ORDER BY id DESC
I have a table named tbl_Question and a column named INT_MARK which has different marks for different questions. Like this:
VH_QUESTION INT_MARK
----------- --------
Q1 2
Q2 4
My question is: How to get a random set of 20 questions whose total sum of marks is 50?
select VH_QUESTION, sum(INT_MARK) from tbl_Question
group by VH_QUESTION
having sum(INT_MARK) > 50
order by rand() limit 1
I think this question may help you - seems a very similar problem.
If that don't work, I'd try to divide the problem in two: first, you make a combinatory of your questions. Then, you filter them by it's sum of points.
I couldn't find, however, how to produce all combinations of the table. I don't know how difficult that would be.
select VH_QUESTION, sum(INT_MARK) from tbl_Question
group by VH_QUESTION
having sum(INT_MARK) >= 50
order by rand() limit 20
Quick answer
SELECT * ,SUM(INT_MARK) as total_mark FROM tbl_Question
GROUP BY VH_QUESTION
HAVING total_mark="50"
ORDER BY RAND()
LIMIT 5
it returns 0 line when no answers are possible but each time it finds one the questionsare random.
You could check the benchmark to see if you can have a faster query for large tables.