1

I'm having a problem with a query running on a little PHP program. When I use * to select all the columns, it takes way more to return the result than when I use just one column.

The query that is running is this:

mysql> SELECT cupom_fiscal_id FROM cupom_fiscal WHERE send_date IS NULL AND travado IS 
FALSE AND status = 0 AND ong_id = 1618 AND data_emissao BETWEEN '2014-04-01' AND '2014-
05-05' LIMIT 1;

In this case it returned:

1 row in set (0.00 sec)

But when I replace the column with '*':

mysql> SELECT * FROM cupom_fiscal WHERE send_date IS NULL AND travado IS FALSE AND 
status = 0 AND ong_id = 1618 AND data_emissao BETWEEN '2014-04-01' AND '2014-05-05' 
LIMIT 1;

1 row in set (1.37 sec)

The funny thing is the result of the query below:

mysql> SELECT * FROM cupom_fiscal WHERE cupom_fiscal_id = (SELECT cupom_fiscal_id FROM 
cupom_fiscal WHERE send_date IS NULL AND travado IS FALSE AND status = 0 AND ong_id = 
1618 AND data_emissao BETWEEN '2014-04-01' AND '2014-05-05' LIMIT 1);

1 row in set (0.00 sec)

What I'm doing wrong?

PS: Sorry for the bad english.

EDIT 1: Posting the 'EXPLAIN' and the 'PROFILING' requested by: @ValerieParham-Thompson

mysql> EXPLAIN SELECT * FROM cupom_fiscal WHERE send_date IS NULL AND travado IS FALSE 
AND status = 0 AND ong_id = 1618 AND data_emissao BETWEEN '2014-04-01' AND '2014-05-05' 
LIMIT 1;
+----+-------------+--------------+-------------+--------------------------------------------------------------------------------+--------------------+---------+------+------+--------------------------------------------------+
| id | select_type | table        | type        | possible_keys                                                                  | key                | key_len | ref  | rows | Extra                                            |
+----+-------------+--------------+-------------+--------------------------------------------------------------------------------+--------------------+---------+------+------+--------------------------------------------------+
|  1 | SIMPLE      | cupom_fiscal | index_merge | fkey_id_ong,status,ong_id,data_emissao,send_date,ong_id_2,ong_id_3,send_date_2 | status,fkey_id_ong | 4,4     | NULL | 3712 | Using intersect(status,fkey_id_ong); Using where |
+----+-------------+--------------+-------------+--------------------------------------------------------------------------------+--------------------+---------+------+------+--------------------------------------------------+
1 row in set (0.00 sec)

Profiling result:

mysql> show profile for query 1;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000121 |
| checking permissions | 0.000015 |
| Opening tables       | 0.000030 |
| init                 | 0.000054 |
| System lock          | 0.000018 |
| optimizing           | 0.000027 |
| statistics           | 0.000282 |
| preparing            | 0.000041 |
| executing            | 0.000014 |
| Sending data         | 0.627346 |
| end                  | 0.000027 |
| query end            | 0.000018 |
| closing tables       | 0.000021 |
| freeing items        | 0.000081 |
| cleaning up          | 0.000012 |
+----------------------+----------+
15 rows in set, 1 warning (0.04 sec)

EDIT 2: I think I got it! I just created an index with the the same fields and in the same order that they appear in the WHERE.

mysql> ALTER TABLE cupom_fiscal ADD INDEX `process` (`send_date`, `travado`, `status`, `ong_id`, `data_emissao`);

I really don't know if that makes any sense, but it solved my problem. The same query that took more than 1 second to return the results now takes < 7ms.

7
  • You're most likely encountering query caching, here. If you attempt to run the SELECT * query twice in a row, you'll probably find that you'll also get 0.00 sec
    – Noah
    Commented May 5, 2014 at 16:45
  • 1
    It is because Primary Key is indexed but other columns are not. Indexed entries always runs fast. To make it faster (I AM NOT SURE THOUGH, BUT COULD BE TRIED), first in a subquery select the Primary Keys, then using an outer query fetch other columns based on those ids like - Select * from table where id in (select id from table where condition ) the query will be even faster if you use Inner join on - (Select * .... ) inner join (select ids from table )
    – Mahmud
    Commented May 5, 2014 at 16:45
  • @Noah Just did and it took the same time, I think it's not cache
    – vsmoraes
    Commented May 5, 2014 at 16:48
  • @Mahmud this is what I did in the last query. Having an outer query just to fetch all the columns is a bit odd, don't you think?
    – vsmoraes
    Commented May 5, 2014 at 16:50
  • @vmroses, might be, I haven't tested it, but since it does not have to fetch all column, the inner might be waaay faster and even though the outer is slower overall time can be less than normal... but I am not sure...needs testing..
    – Mahmud
    Commented May 5, 2014 at 16:52

2 Answers 2

3

Your query:

SELECT * 
FROM cupom_fiscal 
WHERE send_date IS NULL 
  AND travado IS FALSE 
  AND status = 0 
  AND ong_id = 1618 
  AND data_emissao BETWEEN '2014-04-01' AND '2014-05-05' 
LIMIT 1 ;

involves only one table and 5 of its columns in the WHERE clause. Four conditions are equality (=) and the 5th is a range condition (BETWEEN .. AND).


(parenthesis)

The query is not very efficient as it uses the index_merge algorithm, i.e. it uses more than one index (actually two: status and fkey_id_ong) and then "merges" the results using the index_merge/intersect algorithm (Read: Using intersect(status,fkey_id_ong);.) After that operation, it has to also check the actual rows of the table (because, I guess, these two indexes do not include all the 5 columns of the WHERE clause.) This also has a negative effect on efficiency.


The best index for this query would be a 5-column index where the 5th column in data_emissao (the column with the range condition.) The order of the first 4 columns in the index would not matter.

It may matter for other queries but not for this one. So, choose an order that would help other queries as well (if for example you have many queries that use ong_id, use that as the 1st column of the index.

0
1

Your own profile showed the bulk of the execution time was "Sending data", which means transferring records from the server to the client.

Selecting a single integer id column is going to be small, requiring less bandwith than reading all the columns of a the row, which is what 'select *' is short hand for.

This can be especially noticeable if any of your columns are large text or blobs.

1
  • It should make sense but, when executing the query with an outer query fetching the columns, the profiling returns that the "Sending data" was 0.74 and I still got the result in < 7ms.
    – vsmoraes
    Commented May 5, 2014 at 21:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.