由于此设置:
mysql> show global variables like '%indexes';
+-------------------------------+-------+
| Variable_name | Value |
+-------------------------------+-------+
| log_queries_not_using_indexes | ON |
+-------------------------------+-------+
慢查询日志继续接收:
# 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';
尝试解释此查询:
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 |
+----+-------------+-------------+------+---------------+------+---------+------+-------+-------------+
让我感到惊讶的是MySQL没有使用索引的原因:
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
也不起作用:
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 |
+----+-------------+-------------+------+---------------+------+---------+------+-------+-------------+
我必须将此查询拆分为2个操作吗?
答案 0 :(得分:3)
在MySQL
中,您无法在表达式上创建索引,并且优化程序不够智能,无法将查询与两个索引分开。
使用此:
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'
每个查询都使用自己的索引。
您只需将其合并为一个查询:
SELECT *
FROM xbtit_files
WHERE (
soha_id = '6d63dd4ab199190b531752067414d4d6e6568f90'
OR
(soha_id = '' AND info_hash = '6d63dd4ab199190b531752067414d4d6e6568f90')
OR
(soha_id IS NULL AND info_hash = '6d63dd4ab199190b531752067414d4d6e6568f90')
)
并在(soha_id, info_hash)
上创建一个合成索引,以便快速工作。
MySQL
也可以使用index_merge
将两个索引的结果合并在一起,所以即使你没有创建一个,你也有可能在第二个查询的计划中看到这个综合指数。
答案 1 :(得分:2)
因为功能是黑盒子:http://use-the-index-luke.com/sql/where-clause/functions/case-insensitive-search
修改 - 给了你太少的背景,抱歉。
相关部分是:
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.
这适用于所有功能:UPPER,IF,无论......
MySQL已被删除,因为该问题的解决方案(在页面下方进一步描述)不适用于MySQL。
答案 2 :(得分:2)
您可以阅读this以了解OR
运算符在索引数据库时不适用的原因。
答案 3 :(得分:1)
使用函数可能会降低性能(LEFT
函数除外)。尝试此查询
SELECT * FROM xbtit_files WHERE
((soha_id is null OR soha_id = '') AND (info_hash='6d63dd4ab199190b531752067414d4d6e6568f90')) OR
( (soha_id='6d63dd4ab199190b531752067414d4d6e6568f90'))
答案 4 :(得分:0)
主键基于torrent的哈希值,但您可以添加字段ID并使用主键定义它 像这样:
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`);
不要忘记将字段info_hash放到UNIQUE