`
丁林.tb
  • 浏览: 796723 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

MySQL中like语句及相关优化器tips

阅读更多

背景

         MySQL中在对某个字段做包含匹配时可以用like

先看这个结构和结果

 

CREATE TABLE `tb` (

 

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `user_id` bigint(20) DEFAULT NULL,

  `title` varchar(128) NOT NULL,

  `memo` varchar(2000) DEFAULT NULL,

  PRIMARY KEY (`id`),

  KEY `title` (`title`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 

 

mysql> explain select * from tb where title like ‘%abcd%’;

+—-+————-+——-+——+—————+——+———+——+——+————-+

| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |

+—-+————-+——-+——+—————+——+———+——+——+————-+

|  1 | SIMPLE      | tb    | ALL  | NULL          | NULL | NULL    | NULL |    1 | Using where |

+—-+————-+——-+——+—————+——+———+——+——+————-+

1 row in set (1.65 sec)

 

由于like用的是 ‘%xx%’, 不符合前缀匹配的规则,因此用不上索引title,只能作全表扫描。

 

问题

  以上为官方回答。但是如果是在 InnoDB这种聚集索引组织的表中,假设这个表单行很大,比如后面还有若干个类似memo的字段。

  这样聚集索引会很大,导致全表扫描需要读更多的磁盘。而理想情况应该是这个流程

1)       遍历title索引,从中读取和过滤所有title中匹配like条件的id

2)       id到聚簇索引中读数据。

在单行很大,而like能够过滤掉比较多语句的情况下,上面的流程肯定比全表扫描更快,也更省资源。

 

FORCE INDEX行不行?

         第一个反应是用force index

mysql> explain select * from tb force index(title) where title like ‘%abcd%’;

 

+—-+————-+——-+——+—————+——+———+——+——+————-+

| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |

+—-+————-+——-+——+—————+——+———+——+——+————-+

|  1 | SIMPLE      | tb    | ALL  | NULL          | NULL | NULL    | NULL |    1 | Using where |

+—-+————-+——-+——+—————+——+———+——+——+————-+

1 row in set (0.00 sec)

 

 

         显然不行。原因是通常情况force index只能从possible_keys中强制选择某一个索引,但是这个查询的possible_keysNULL, force index 无效。

 

覆盖索引

   我们想到覆盖索引,试验这个语句。

mysql> explain select id from tb  where title like ‘%abcd%’;                  

 

+—-+————-+——-+——-+—————+——-+———+——+——+————————–+

| id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows | Extra                    |

+—-+————-+——-+——-+—————+——-+———+——+——+————————–+

|  1 | SIMPLE      | tb    | index | NULL          | title | 386     | NULL |    1 | Using where; Using index |

+—-+————-+——-+——-+—————+——-+———+——+——+————————–+

1 row in set (0.00 sec)

 

我们看到这个语句用上了title索引,而且Using index表明用上了覆盖索引。

 

有同学可能会疑惑,这里possible_keysNULL, 为什么key用上了title,应了那句“nothing imposible?

 

实际上在MySQL优化器里面专门加了这一段,在type= JT_ALL时,会特别扫一下所有能够满足的覆盖索引,并找长度最短的那个。

这么做的考虑就是基于选择小的索引,减少读盘。重要的是,这个优化对于现有的引擎是通用的。

 

因此上面说的“通常情况下”的例外就是:force index可以强制使用覆盖索引。比如常见的 select count(*) from tb. 这时候你force index所有已存在的索引都是可以生效的。

 

权宜之计

         了解了覆盖索引的效果,我们可以把查询改写为如下,以满足我们最开始希望的执行流程。

mysql> explain Select * from (select id from tb where title like ‘%a’) t1 join tb  using (id);

 

+—-+————-+————-+——–+—————+————+———+——-+——+————————–+

| id | select_type | table       | type   | possible_keys | key        | key_len | ref   | rows | Extra                    |

+—-+————-+————-+——–+—————+————+———+——-+——+————————–+

|  1 | PRIMARY     | <derived2>  | system | NULL          | NULL       | NULL    | NULL  |    1 |                          |

|  1 | PRIMARY     | tb | const  | PRIMARY       | PRIMARY    | 4       | const |    1 |                          |

|  2 | DERIVED     | tb | index  | NULL          | idx_userid | 386     | NULL  |    1 | Using where; Using index |

+—-+————-+————-+——–+—————+————+———+——-+——+————————–+

3 rows in set (0.00 sec)

 

 

explain结果中看执行流程是按照我们之前描述的那样,但是引入了JOIN

 

 补充说明

JOIN写法还会引入primary key查询的时候是随机查询,因此最终的效率受like的过滤效果影响。

这个改写对性能的提升效果取决于要使用的索引与总数据量的大小比较,需要作应用测试。

 

分享到:
评论
3 楼 丁林.tb 2012-09-29  
jinnianshilongnian 写道
oracle中没有这种覆盖索引吧?

有的。
只是oracle就直接最原始的写法就能够满足我们要的那个最优流程了
2 楼 jinnianshilongnian 2012-09-28  
oracle中没有这种覆盖索引吧?
1 楼 jinnianshilongnian 2012-09-28  
FORCE INDEX 不行的原因 是因为那个 * 造成的查询的数据不在索引里

引用
这个改写对性能的提升效果取决于要使用的索引与总数据量的大小比较,需要作应用测试。

有木有12306的同学测试下  哈哈

相关推荐

    Effective MySQL之SQL语句最优化.pdf

    尽管如此,我将基于标题和描述中提供的关键词“Effective MySQL之SQL语句最优化”来构建知识点。 1. SQL语句最优化的概念:在数据库管理中,对SQL语句进行优化是提高数据库性能的关键环节。最优化的SQL语句能够在...

    mysql insert语句mysql insert语句mysql insert语句mysql insert语句mysql in

    mysql insert语句mysql insert语句mysql insert语句mysql insert语句mysql insert语句mysql insert语句mysql insert语句mysql insert语句mysql insert语句mysql insert语句mysql insert语句mysql insert语句mysql ...

    Effective MySQL之SQL语句最优化(高清)

    《Effective MySQL之SQL语句最优化》提供了很多可以用于改进数据库和应用程序性能的最佳实践技巧,并对这些技巧做了详细的解释。《Effective MySQL之SQL语句最优化》希望能够通过一步步详细介绍SQL优化的方法,帮助...

    《Effective MySQL之SQL语句最优化》手册

    《Effective MySQL之SQL语句最优化》是一本深入探讨如何提升数据库性能的专业手册,它针对SQL语句的优化提供了一系列实用且高效的策略。在数据库管理领域,SQL优化是提升系统性能的关键环节,尤其是在处理大数据量时...

    《Effective MySQL之SQL语句最优化》数据库SQL

    《Effective MySQL之SQL语句最优化》是一本深入探讨如何提升数据库性能,特别是针对SQL查询进行优化的专业书籍。在数据库管理中,SQL语句的优化是至关重要的,它直接影响到系统的响应速度和整体效率。本篇文章将依据...

    mysql优化sql语句的优化(索引,常用小技巧.)

    ### MySQL优化之SQL语句与索引优化 #### 数据库设计合理性 在MySQL数据库的优化过程中,合理设计数据库(表)至关重要。一个合理的数据库设计能够有效地提高查询性能、减少数据冗余并确保数据完整性。 - **3NF**...

    mysql批量修改语句

    mysql批量语句,传入list 批量修改mysql批量语句,传入list 批量修改mysql批量语句,传入list 批量修改

    mysql常用性能查询语句

    本文总结了一些常用的 MySQL 性能查询语句,帮助数据库管理员和开发人员更好地了解和优化数据库性能。 1. 查看 MySQL 本次启动后的运行时间(单位:秒) 使用语句:show status like 'uptime'; 该语句可以查看 ...

    MySQL 数据库 like 语句通配符模糊查询小结

    MySQL 报错:Parameter index out of range (1 > number of parameters, which is 0)——MySQL 数据库 like 语句通配符模糊查询小结 前言 今天在使用MySQL语句执行增删改查操作时,控制台报出了以下错误:Parameter...

    MySQL常用sql语句生成器

    下面将详细介绍MySQL中的SQL语句及其生成器的相关知识。 1. SQL基础概念 SQL,全称为结构化查询语言,是用于创建、查询、更新和删除数据库中数据的标准语言。它分为DQL(查询语言)、DML(数据操纵语言)、DDL...

    sql语句优化 mssql优化 mysql优化 oracle优化

    sql语句优化.chmmssql优化 mysql优化 oracle优化

    MySQL SQL语句练习题及答案

    MySQL SQL语句练习题及答案 本资源提供了 MySQL SQL 语句的练习题及答案,涵盖了创建表、插入数据、删除数据、更新数据、查询数据等多方面的知识点。 一、创建表 在 MySQL 中,创建表使用 CREATE TABLE 语句。...

    Oracle Sql语句转换成Mysql Sql语句

    OracleSqlConvert4MysqlSqlTool.java这个源码工具,根据描述,应该是实现了自动读取Oracle SQL语句,分析其结构,并根据MySQL的语法规则进行转换,然后将转换后的SQL语句保存到指定的目标文件中。这个工具简化了手动...

    MySQL中索引优化distinct语句及distinct的多字段操作

    在一些情况下,MySQL可以使用索引优化DISTINCT操作,但需要活学活用.本文涉及一个不能利用索引完成DISTINCT操作的实例.   实例1 使用索引优化DISTINCT操作 create table m11 (a int, b int, c int, d int, primary ...

    mysql语句转postgres的工具

    在这个过程中,`MysqlToPostgresUtil`工具扮演着重要的角色,它能帮助我们将MySQL的DDL(Data Definition Language)语句转换为PostgreSQL兼容的格式,从而简化迁移过程。 MySQL和PostgreSQL虽然都是关系型数据库...

    《Effective MySQL之SQL语句最优化》PDF

    《EffectiveMySQL之SQL语句最优化》提供了很多可以用于改进数据库和应用程序性能的最佳实践技巧,并对这些技巧做了详细的解释。《EffectiveMySQL之SQL语句最优化》希望能够通过一步步详细介绍SQL优化的方法,帮助...

    提升MYSQL查询效率的10个SQL语句优化技巧.doc

    以下是十个 SQL 语句优化技巧来提升 MYSQL 查询效率: 1. 优化 MySQL 查询缓存 MySQL 查询缓存可以启用高速查询缓存,让数据库引擎在后台悄悄的处理是提高性能的最有效方法之一。当同一个查询被执行多次时,如果...

    解决MySql大数据Like查询慢的问题

    总结,优化MySQL中的LIKE查询需要综合考虑查询语句的优化、索引的合理使用以及在应用程序层面进行预处理。结合JAVA模拟LIKE的策略,可以在不改变原有查询逻辑的情况下,显著提高查询效率。在实践中,应根据具体业务...

Global site tag (gtag.js) - Google Analytics