如何强制MySQL忽略所有索引?


12

我已经阅读了有关FORCE索引的文章,但是如何强制MySQL进行IGNORE ALL索引呢?

我尝试过SELECT * FROM tbl IGNORE INDEX(*),但是没有成功。

至于为什么我(和其他人)需要这样做:例如,我需要像这样通过tld总结引荐来源统计信息:

SELECT 
    count(*) as c, 
    SUBSTRING
    (
        domain_name, 
        LENGTH(domain_name) - LOCATE('.', REVERSE(domain_name)) + 2
    ) as tld
FROM `domains_import` 
    IGNORE INDEX(domain_name)
GROUP BY tld
ORDER BY c desc
LIMIT 100

...但是我始终必须查看定义了哪些索引,或者确定将通过Explain使用哪些索引。简单地编写IGNORE INDEX ALL而不关心就非常方便。

有人知道语法或技巧吗?(数十行通过MySQL定义表的行实际上不是捷径)。

聊天讨论中添加:

贝克马克:

  • 无索引= 148.5秒

  • 索引= 180秒,并且仍在与发送数据一起运行SSD阵列是如此强大,以至于您几乎不需要关心数据缓存...

基准的定义:

CREATE TABLE IF NOT EXISTS `domains_import` (
`domain_id` bigint(20) unsigned NOT NULL,
`domain_name` varchar(253) CHARACTER SET ascii COLLATE ascii_bin NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `domains_import`
ADD PRIMARY KEY (`domain_id`),
ADD UNIQUE KEY `domain_name` (`domain_name`);

ALTER TABLE `domains_import`
MODIFY `domain_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT;

InnoDB,带有索引的测试(没有USE INDEX()或类似的东西)仍在运行250秒,我只是杀死了它。

Answers:


24

绝对不清楚为什么要这样做USE INDEX (),但是您可以使用提示告诉优化器不要使用任何索引。来自MySQL文档:索引提示

省略index_listUSE INDEX语法上是有效表示“不使用索引”。省略index_list FORCE INDEX或是IGNORE INDEX语法错误。

您的查询变为:

SELECT count(*) AS c, 
       substring_index(domain_name, '.', -1) AS tld
FROM domains_import 
       USE INDEX ()        -- use no indexes
GROUP BY tld
ORDER BY c DESC
LIMIT 100 ;

旁注:复杂的表达式:

SUBSTRING(domain_name, LENGTH(domain_name) - LOCATE('.', REVERSE(domain_name)) + 2) 

可以从4个函数调用简化为1:

SUBSTRING_INDEX(domain_name, '.', -1)

1
当MySQL 5.7.10优化器在删除一些LEFT JOIN我的查询计划时更改了最坏的查询计划时,这对我很有用。USE INDEX()使MySQL在20K行表和1-to-1上执行表扫描,JOIN而不是在两个索引之间交叉500行。快了20倍。
Xenos

2

您也可以嵌入 WHERE 1=1

SELECT 
    count(*) as c, 
    SUBSTRING
    (
        domain_name, 
        LENGTH(domain_name) - LOCATE('.', REVERSE(domain_name)) + 2
    ) as tld
FROM `domains_import` 
WHERE 1=1
GROUP BY tld
ORDER BY c desc
LIMIT 100

ypercube刚问我

Rolando,MySQL的优化器太笨了,以至于简单的,始终为真的条件将禁止使用索引?

是的,但是您给了MySQL一个非常愚蠢的查询。1=1将恢复为聚集索引。尽管如此,还有另一种方法,但这需要对Optimizer稍加恶意。

SELECT 
    count(*) as c, 
    SUBSTRING
    (
        domain_name, 
        LENGTH(domain_name) - LOCATE('.', REVERSE(domain_name)) + 2
    ) as tld
FROM `domains_import` 
WHERE domain_name = domain_name
GROUP BY tld
ORDER BY c desc
LIMIT 100

这肯定会把每个索引扔到总线下,因为domain_name要检查每一行的值。如果domain_name已建立索引,则必须WHERE column_name=column_name为根本没有建立索引的列选择一个列。

我只是在登台服务器的大桌子上尝试过

mysql > explain SELECT COUNT(1) FROM VIDEO WHERE EMBEDDED_FLG=EMBEDDED_FLG;
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | VIDEO | ALL  | NULL          | NULL | NULL    | NULL | 354327 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.00 sec)

未选择索引


Rolando,MySQL的优化器太笨了,以至于简单的,始终为真的条件将禁止使用索引?
ypercubeᵀᴹ

@ypercube是的,但是您必须对查询进行足够的虚拟化,以使其发生。
RolandoMySQLDBA 2015年

1
嘿,我赞成yercube的回答。我的回答只是另一种方式,它解释了优化器的漏洞。
RolandoMySQLDBA'Aug

1
Rolando,不是真的:将使用索引:SQLfiddle。即使您使某些事情变得更复杂,诸如WHERE id+0 = id*1索引仍将被使用,并且Using where还会出现一个额外的内容。
ypercubeᵀᴹ

4
@PaulWhite会的。(这很愚蠢,但不是那么愚蠢;)这也许就是为什么Roalndo的查询不使用索引的原因,该列必须已定义为NULL。
ypercubeᵀᴹ

0

假设您具有以下两个索引:

ADD PRIMARY KEY (`domain_id`),
ADD UNIQUE KEY `domain_name` (`domain_name`);

然后,优化器的功能并不重要。它必须扫描基本上相同数量的东西。

情况1:执行表扫描(或使用domain_id):将扫描(标识,名称)对,查找所有名称,进行SUBSTRING..LOCATE,GROUP BY,最后进行ORDER BY。GROUP BY和ORDER BY可能每个都需要一个tmp表和文件排序。检查EXPLAIN SELECT ...是否可以。

情况2:它执行(域名称)的索引扫描:该索引实际上包含(名称,id)对-因为InnoDB隐式地将PK放在任何辅助键的末尾。其余处理与案例1类似。

一件事可能会有所不同-两个BTree的大小。不要SHOW TABLE STATUS LIKE domains_import看DATA_LENGTH(对于病例1)和Index_length(案例2)。较大的BTree将较慢。

另一件事可能与众不同-缓存。什么是值innodb_buffer_pool_size?你有多少RAM?数据(或索引)是否可以包含在缓冲池中。(或者由于表/索引扫描而占37%?)如果适合,请运行两次查询。由于没有击中磁盘(缓存),第二次的速度大约是10倍。

如果这是一项一次性任务,SSD将提供帮助。如果没有,则可以缓存整个表,那么在buffer_pool加载后,它将无济于事。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.