Because of this setting:
mysql> show global variables like '%indexes';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| log_queries_not_using_indexes | ON |
+-------------------------------+-------+
The slow queries log keep receiving:
# Time: 120607 16:58:30
# User@Host: xbtit[xbtit] @ [123.30.53.244]
# Query_time: 0 Lock_time: 0 Rows_sent: 1 Rows_examined: 16006
SELECT * FROM xbtit_files WHERE IF(soha_id is null OR soha_id = '', info_hash, soha_id)='6d63dd4ab199190b531752067414d4d6e6568f90';
Trying to explain this query:
mysql> EXPLAIN SELECT * FROM xbtit_files WHERE IF(soha_id is null OR soha_id = '', info_hash, soha_id)='6d63dd4ab199190b531752067414d4d6e6568f90';
+----+-------------+-------------+------+---------------+------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+------+---------------+------+---------+------+-------+-------------+
| 1 | SIMPLE | xbtit_files | ALL | NULL | NULL | NULL | NULL | 16006 | Using where |
+----+-------------+-------------+------+---------------+------+---------+------+-------+-------------+
What surprised me is why MySQL not using indexes:
mysql> show index from xbtit_files;
+-------------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| xbtit_files | 0 | PRIMARY | 1 | info_hash | A | 16006 | NULL | NULL | | BTREE | |
| xbtit_files | 1 | filename | 1 | filename | A | 16006 | NULL | NULL | YES | BTREE | |
| xbtit_files | 1 | category | 1 | category | A | 1 | NULL | NULL | | BTREE | |
| xbtit_files | 1 | uploader | 1 | uploader | A | 16 | NULL | NULL | | BTREE | |
| xbtit_files | 1 | bin_hash | 1 | bin_hash | A | 16006 | 20 | NULL | | BTREE | |
| xbtit_files | 1 | ix_sohaid | 1 | soha_id | A | 16006 | NULL | NULL | YES | BTREE | |
+-------------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
FORCE INDEX
also doesn't work:
mysql> EXPLAIN SELECT * FROM xbtit_files force index (PRIMARY) WHERE IF(soha_id is null OR soha_id = '', info_hash, soha_id)='6d63dd4ab199190b531752067414d4d6e6568f90';
+----+-------------+-------------+------+---------------+------+---------+------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+------+---------------+------+---------+------+-------+-------------+
| 1 | SIMPLE | xbtit_files | ALL | NULL | NULL | NULL | NULL | 16006 | Using where |
+----+-------------+-------------+------+---------------+------+---------+------+-------+-------------+
Must I split this query into 2 operations?
In MySQL
, you cannot create indexes on expressions, and the optimizer is not smart enough to split your query against two indexes.
Use this:
SELECT *
FROM xbtit_files
WHERE soha_id = '6d63dd4ab199190b531752067414d4d6e6568f90'
UNION ALL
SELECT *
FROM xbtit_files
WHERE soha_id = ''
AND info_hash = '6d63dd4ab199190b531752067414d4d6e6568f90'
UNION ALL
SELECT *
FROM xbtit_files
WHERE soha_id IS NULL
AND info_hash = '6d63dd4ab199190b531752067414d4d6e6568f90'
Each query uses its own index.
You can just combine it into a single query:
SELECT *
FROM xbtit_files
WHERE (
soha_id = '6d63dd4ab199190b531752067414d4d6e6568f90'
OR
(soha_id = '' AND info_hash = '6d63dd4ab199190b531752067414d4d6e6568f90')
OR
(soha_id IS NULL AND info_hash = '6d63dd4ab199190b531752067414d4d6e6568f90')
)
and create a composit index on (soha_id, info_hash)
for this to work fast.
MySQL
is also able to merge results from two indexes together, using index_merge
, so there is a chance you would see this in the plan for the second query even if you don't create a composite index.
Because functions are black boxes: http://use-the-index-luke.com/sql/where-clause/functions/case-insensitive-search
Edit - gave you too little context, sorry.
The relevant part is:
It is a trap we all fall into. We instantly recognize the relation between
LAST_NAME and UPPER(LAST_NAME) and expect the database to “see” it as well.
In fact, the optimizer’s picture is more like that:
SELECT first_name, last_name, phone_number
FROM employees
WHERE BLACKBOX(...) = 'WINAND';
The UPPER function is just a black box. The parameters to the function are
not relevant because there is no general relationship between the function’s
parameters and the result.
That applies to all functions: UPPER, IF, whatever...
MySQL is crossed out because the solution to that problem, which is described further down the page, does not work with MySQL.
您可以阅读此内容以了解为什么OR
运算符不适用于索引DB。
use functions in where could be slow down performance(except LEFT
function).try this query
SELECT * FROM xbtit_files WHERE
((soha_id is null OR soha_id = '') AND (info_hash='6d63dd4ab199190b531752067414d4d6e6568f90')) OR
( (soha_id='6d63dd4ab199190b531752067414d4d6e6568f90'))
The primary key is based on the hash of the torrent but you can add a field id and define it with primary key
Like this:
ALTER TABLE `xbtit_files` DROP PRIMARY KEY;
ALTER TABLE `xbtit_files` ADD `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST;
ALTER TABLE `xbtit_files` ADD UNIQUE (`info_hash`);
Do not forget to put the fields info_hash to UNIQUE
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.