Order by performance problems - mysql

I have an index problem with my order by statement. I have this query witch is runing fast:
SELECT name from members where kat = 2 order by date DESC;
I have a composite index on members table:
kat_index(kat,date);
Now my aplication has changed and i have added a query like this:
SELECT name from members where kat = 2 order by logged_in DESC, status DESC, date DESC;
Now the query i slow because it's using filesort. So the question is... What type of index should i add to satisfy both queries?

You should have two indexes:
(kat, date)
(kat, logged_in, status, date)
Each query will use the index that is best for that query.

You cannot cover both queries with one index. You must form a leftmost prefix on the composite index along with the ORDER BY clause as well.

Related

MySQL table with composite primary key LIMIT 1 is very slow while Limit 2 is fast

I have ProductInfo table with following indexes -
Primary: ProductCode, Model, Added_Date, id
Index: id
The composite primary key are the columns I use in the following query
SELECT * FROM ProductInfo WHERE
ProductCode='45678' AND
Model='PQA-1' AND
(Added_Date >='2021-08-01 00:00:00' AND Added_Date <='2021-08-14 23:59:59')
ORDER BY Added_Date ASC;
This query works pretty fine
Problem
The following query is fast
select * from ProductInfo WHERE ProductCode="45678" order by id desc limit 1;
Here is the explain
But the following query is very very slow. Please note that query is same but just ProductCode is different
select * from ProductInfo WHERE ProductCode="78342" order by id desc limit 1;
Here is the explain.
However, same query with Limit 2 is fast
select * from ProductInfo WHERE ProductCode="78342" order by id desc limit 2;
Here is the explain
What is the cause? Is my indexing correct? What will be the solution?
Thanks
The first query benefits from this index:
PRIMARY KEY(ProductCode, Model, Added_Date)
All the other queries could not fully benefit from either of your indexes. The Optimizer guessed at one index in one case; the other index in the other. This would work well for both cases:
INDEX(ProductCode, Id)
One reason for the timing differences is the distribution of data in the table. Your examples may not show the same timings if you change the 78342 to some other value.
The new index I recommend will make those queries "fast" regardless of the ProductCode searched on. And "Rows" will say "1" or "2" instead of about "25000".
It sounds like there are about 25K rows with ProductCode = 78342.

Database: Sorting on non-indexed column

Does creating index on a column which is there in sort order improves performance? I need to know this for Mysql, Postgresql and Oracle database.
E.g query:
select * from article_comments where article_id = 245 order by date_created desc limit 30;
In article_comments table, article_id is an indexed field, where as date_created is not.
If we create an index on date_created, will it improve performance.
Table size is around 5-7 million rows.
Does creating index on a column which is there in sort order improves
performance?
A general answer is: it depends on many factors, esspecialy on conditions used in WHERE clause.
In case of your query an index on date_created column doesn't eliminate a sort operation due to where article_id = 245 clause.
In this case you need to create a multicolum index in order to skip sorting:
CREATE INDEX somename ON article_comments(article_id, date_created DESC)
I can tell only for Oracle. Yes an Index can make your sorting faster.
In this example Function-Based Index for Language-Dependent Sorting Oracle shows an index which intention is only to improve performance of an ORDER BY operation.
Another example regarding sorting is shown here: Full Index Scan

MySQL query using filesort and temporary

I am using a simple MySQL query, but the performance is realy bad because of using ORDER BY. I can't figure out why MySQL is using filesort and temporary.
My query is:
EXPLAIN
SELECT * FROM Events
INNER JOIN EventLogFiles ON ServerID = 42
AND Events.LogFileID = EventLogFiles.LogFileID
ORDER BY ReportID DESC , TimeWritten DESC
LIMIT 100
This is the output of EXPLAIN:
Table Events structure
Table Events indexes
Table EventLogFiles structure
Table EventLogFiles indexes
UPDATE:
I tried to create two new indexes, but both still force MySQL to use filesort and temporary.
ALTER TABLE Events ADD INDEX `ReportID_TimeWritten_ServerID_LogFileID` ( ReportID DESC, TimeWritten DESC, ServerID, LogFileID)
ALTER TABLE Events ADD INDEX `ServerID_LogFileID_ReportID_TimeWritten` ( ServerID, LogFileID, ReportID DESC, TimeWritten DESC)
In order to utilize the index for both selection and sorting, you need to have all of the following columns in a multi-column index on Events: (ServerID, LogFileID, ReportID, TimeWritten).
Currently, MySQL cannot utilize the existing multi-column index because it doesn't include LogFileID, which is in your ON clause.
If you ever have problems where MySQL is selecting from EventLogFiles first, you can change the INNER JOIN to a STRAIGHT JOIN to ensure that MySQL always elects from Events first, using your index.
In order to get that working without temp table and file sort, you must to create an index (ServerID, LogFileID, ReportID) and TimeWritten must to be sequential like the auto_increment that you have been using in ReportID, so making the ORDER BY ReportID(PK - Order Physical) you must remove the filesort.

mysql index optimization problem

I have a query like below.
SELECT a,b,c,d
FROM table_name
WHERE e=1 AND f=0
GROUP BY d
ORDER BY id DESC LIMIT 5
when I indexed (e,f,d) query time : 4 sec.
when I indexed (d,e,f) query time : 20 sec.
So that I understand that index colums ordering is important.
Which index would be better for mysql?
Indexes should first satisfy the where clause, then the group or order clause. Always use EXPLAIN on your query to see how it is performed

Can MySQL use index in a RANGE QUERY with ORDER BY?

I have a MySQL table:
CREATE TABLE mytable (
id INT NOT NULL AUTO_INCREMENT,
other_id INT NOT NULL,
expiration_datetime DATETIME,
score INT,
PRIMARY KEY (id)
)
I need to run query in the form of:
SELECT * FROM mytable
WHERE other_id=1 AND expiration_datetime > NOW()
ORDER BY score LIMIT 10
If I add this index to mytable:
CREATE INDEX order_by_index
ON mytable ( other_id, expiration_datetime, score);
Would MySQL be able to use the entire order_by_index in the query above?
It seems like it should be able to, but then according to MySQL's documentation: "The index can also be used even if the ORDER BY does not match the index exactly, as long as all of the unused portions of the index and all the extra ORDER BY columns are constants in the WHERE clause."
The above passage seems to suggest that index would only be used in a constant query while mine is a range query.
Can anyone clarify if index would be used in this case? If not, any way I could force the use of index?
Thanks.
MySQL will use the index to satisfy the where clause, and will use a filesort to order the results.
It can't use the index for the order by because you are not comparing expiration_datetime to a constant. Therefore, the rows being returned will not always all have a common prefix in the index, so the index can't be used for the sort.
For example, consider a sample set of 4 index records for your table:
a) [1,'2010-11-03 12:00',1]
b) [1,'2010-11-03 12:00',3]
c) [1,'2010-11-03 13:00',2]
d) [2,'2010-11-03 12:00',1]
If I run your query at 2010-11-03 11:00, it will return rows a,c,d which are not consecutive in the index. Thus MySQL needs to do the extra pass to sort the results and can't use an index in this case.
Can anyone clarify if index would be used in this case? If not, any way I could force the use of index?
You have a range in filtering condition and the ORDER BY not matching the range.
These conditions cannot be served with a single index.
To choose which index to create, you need to run these queries
SELECT COUNT(*)
FROM mytable
WHERE other_id = 1
AND (score, id) <
(
SELECT score, id
FROM mytable
WHERE other_id = 1
AND expiration_datetime > NOW()
ORDER BY
score, id
LIMIT 10
)
and
SELECT COUNT(*)
FROM mytable
WHERE other_id = 1
AND expiration_datetime >= NOW()
and compare their outputs.
If the second query yields about same or more values as the first one, then you should use an index on (other_id, score) (and let it filter on expiration_datetime).
If the second query yields significantly less values than the first one, you should use an index on (other_id, expiration_datetime) (and let it sort on score).
This article might be interesting to you:
Choosing index
Sounds like you've already checked the documentation and setup the index. Use EXPLAIN and see...
EXPLAIN SELECT * FROM mytable
WHERE other_id=1 AND expiration_datetime > NOW()
ORDER BY score LIMIT 10