I'm trying this simple query:
SELECT * FROM `Users` WHERE MATCH (`User`) AGAINST ('User') LIMIT 5
I have a FULLTEXT index on column User.
EXPLAIN SELECT returns:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE Users fulltext user_comparator user_comparator 0 1 Using where
What am I doing wrong?
if 50% or more of your column user has the phrase 'User' in it, it would be considered common and would not match any rows. if you are dealing with a small amount of data you could always use the 'like' comparator.
Related
In this example, id is pk.
And the total number of rows is 541.
In the first example below, all rows with id > 50 are accessed, but because of limit 5, the
rows value is expected to be 5. What's the problem?
The order by column is pk, and the where comparison column is also pk.
=======
explain select * from mytable where id > 50 order by id limit 5;
select_type
table
partitions
type
possible_keys
key
key_len
ref
rows
filtered
Extra
SIMPLE
cpc_pre_booking
range
PRIMARY
PRIMARY
8
491
100
Using where
explain select * from mytable where id > 200 order by id limit 5;
select_type
table
partitions
type
possible_keys
key
key_len
ref
rows
filtered
Extra
SIMPLE
cpc_pre_booking
range
PRIMARY
PRIMARY
8
341
100
Using where
explain select * from mytable where id > 400 order by id limit 5;
select_type
table
partitions
type
possible_keys
key
key_len
ref
rows
filtered
Extra
SIMPLE
cpc_pre_booking
range
PRIMARY
PRIMARY
8
141
100
Using where
I want to know what am i missing
The "Rows" in EXPLAIN are estimates based on statistics, and usually without taking into account LIMIT value. Don't trust them very far.
After the fact, the slowlog will provide exact "Rows_examined" and "Rows_returned".
Here's a another way (also by actually running the query):
FLUSH STATUS;
SELECT ...;
SHOW SESSION STATUS LIKE 'Handler%';
As mention in the title, I would like to know any solution for this by not using store prodecure, temporarily table etc.
Compare Query#1 and Query#3, Query#3 get worst performance result. Does it have any workaround to put in variable but without impact the performance result.
Schema (MySQL v5.7)
create table `order`(
id BIGINT(20) not null auto_increment,
transaction_no varchar(20) not null,
primary key (`id`),
unique key uk_transaction_no (`transaction_no`)
);
insert into `order` (`id`,`transaction_no`)
value (1,'10001'),(2,'10002'),(3,'10003'),(4,'10004');
Query #1
explain select * from `order` where transaction_no in ('10001','10004');
id
select_type
table
partitions
type
possible_keys
key
key_len
ref
rows
filtered
Extra
1
SIMPLE
order
range
uk_transaction_no
uk_transaction_no
22
2
100
Using where; Using index
Query #2
set #transactionNos = "10001,10004";
There are no results to be displayed.
Query #3
explain select * from `order` where find_in_set(transaction_no, #transactionNos);
id
select_type
table
partitions
type
possible_keys
key
key_len
ref
rows
filtered
Extra
1
SIMPLE
order
index
uk_transaction_no
22
4
100
Using where; Using index
Short Answer: See Sargeability
Long Answer:
MySQL makes no attempt to optimize an expression when an indexed column when it is hidden inside a function call such as FIND_IN_SET(), DATE(), etc. Your Query 3 will always be performed as a full table scan or a full index scan.
So the only way to optimize what you are doing is to construct
IN ('10001','10004')
That is often difficult to achieve when "binding" a list of values. IN(?) will not work in most APIs to MySQL.
I have the following table with Index on id and Foreign Key on activityID:
comment (id, activityID, text)
and the following query:
SELECT <cols> FROM `comment` WHERE `comment`.`activityID` = 1257 ORDER BY `id` DESC LIMIT 20;
I basically want to get only the first 20 comments for this activity that has 1165, however, this is the result of a describe:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE comment ref activityID activityID 4 const 1165 NULL
Essentially, it is looking through all comments for this activity before deciding to limit it.
We tested this query under high load when an activity has 200,000 comments and the query takes 5+ seconds, whereas on the same load, an activity with 30 comments takes a couple of ms.
PS: If I remove the WHERE clause, an EXPLAIN says it will only lookup a single row (don't know if that's the case really):
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE comment index NULL PRIMARY 4 NULL 1 NULL
Is it possible to optimize this kind of query in any way?
Thank you.
The ordering is causing the slowness.
The query uses the activityID index to find all the rows with that ID. Then it has to read all 200,000 comments and sort them by id to find the last 20.
Add a composite index so it can use an index for the ordering:
ALTER TABLE comment ADD INDEX (activityID, id);
Note that you will no longer need the index on activityID by itself, since it's a prefix of this new index.
Use offset
SELECT <cols> FROM `comment` WHERE `comment`.`activityID` = 1257 ORDER BY `id` DESC LIMIT 0,20;
In limit clause add 0 as an offset to get only the first 20 comments
Just add two separate indexes on activityID and id. That should help you in ORDER BY too. There is no hard and fast rules in optimizations, but you need to try various methods.
Do it this way:
ALTER TABLE comment ADD INDEX (id);
ALTER TABLE comment ADD INDEX (activityID);
I think this will help.
I'm trying to get this query to use an index.
explain SELECT SQL_NO_CACHE * FROM products WHERE (stock_disabled = 1 OR negative_stock_allowed = 1 OR stock > 0)
This is what it returns:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE p ALL multi_index NULL NULL NULL 2890 Using where
The multi_index is an that contains stock_disabled, negative_stock_allowed and stock in the same order. I think the index is not working because of the multiple OR statements. What can I do here?
"USE INDEX foo" if you explicitly want to use an index
SELECT * FROM products USE INDEX(`multi_index`)
I tried the SQL code:
explain SELECT * FROM myTable LIMIT 1
As a result I got:
id select_type table type possible_keys key key_len ref **rows**
1 SIMPLE myTable ALL NULL NULL NULL NULL **32117**
Do you know why the query would run though all rows instead of simply picking the first row?
What can I change within the query (or in my table) to reduce the line amount for a similar result?
The rows count shown is only an estimate of the number of rows to examine. It is not always equal to the actual number of rows examined when you run the query.
In particular:
LIMIT is not taken into account while estimating number of rows Even if you have LIMIT which restricts how many rows will be examined MySQL will still print full number.
Source
When the query actually runs only one row will be examined.
Edited for use of subselect:
Assuming the primary key is "my_id" , use WHERE. For instance:
select * from mytable
where my_id = (
select max(my_id) from mytable
)
While this seems less efficient at first, the result is as such in explain, resulting in just one row returned and a read on the index to find max. I do not suggest doing this against partitioned tables in MySQL:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY mytable const PRIMARY PRIMARY 4 const 1
2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL Select tables optimized away