使用索引时,有以下一些技巧和注意事项:

(1)越小的数据类型通常更好:越小的数据类型通常在磁盘、内存和CPU缓存中都需要更少的空间,处理起来更快。
(2)简单的数据类型更好:整型数据比起字符,处理开销更小,因为字符串的比较更复杂。在MySQL中,应该用内置的日期和时间数据类型,而不是用字符串来存储时间;以及用整型数据类型存储IP地址。
(3)尽量避免NULL:应该指定列为NOT NULL,除非你想存储NULL。在MySQL中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较运算更加复杂。你应该用0、一个特殊的值或者一个空串代替空值。
(4)索引不会包含有NULL值的列。

但是如果是同样的sql如果在之前能够使用到索引,那么现在使用不到索引,以下几种主要情况:

1. 随着表的增长,where条件出来的数据太多,大于15%,使得索引失效(会导致CBO计算走索引花费大于走全表)

2. 统计信息失效      需要重新搜集统计信息

3. 索引本身失效      需要重建索引

下面是一些不会使用到索引的原因
索引失效
1) 没有查询条件,或者查询条件没有建立索引;
2) 在查询条件上没有使用引导列
3) 查询的数量是大表的大部分,应该是30%以上。 
4) 索引本身失效 
5) 查询条件使用函数在索引列上(见12) 
6) 对小表查询 
7) 提示不使用索引 
8) 统计数据不真实 
9) CBO计算走索引花费过大的情况。其实也包含了上面的情况,这里指的是表占有的block要比索引小。 
10)隐式转换导致索引失效.这一点应当引起重视.也是开发中经常会犯的错误. 由于表的字段tu_mdn定义为varchar2(20), 
但在查询时把该字段作为number类型以where条件传给mysql,这样会导致索引失效. 
错误的例子:select * from test where tu_mdn=13333333333; 
正确的例子:select * from test where tu_mdn='13333333333'; 
11)对索引列进行运算导致索引失效,我所指的对索引列进行运算包括(+,-,*,/,! 等) 
错误的例子:select * from test where id-1=9; 
正确的例子:select * from test where id=10; 
12)使用mysql内部函数导致索引失效.对于这样情况应当创建基于函数的索引. 
错误的例子:select * from test where round(id)=10; 
说明,此时id的索引已经不起作用了 正确的例子:首先建立函数索引, 
create index test_id_fbi_idx on test(round(id)); 
然后 select * from test where round(id)=10; 这时函数索引起作用了

13)如果MySQL估计使用索引比全表扫描更慢,则不使用索引。例如如果列key_part1均匀分布在1到100之间,查询时使用索引就不是很好

  1. mysql>select * from table_name where key_part1>1 and key_part<90;

14)如果使用MEMORY/HEAP表并且where条件中不使用“=”进行索引列,那么不会用到索引。Heap表只有在“=”的条件下会使用索引。因为用的是哈希索引。

15)用or分割开的条件,如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到

表见mysql索引之五:组合索引怎么应该怎么选取引导列

  1. mysql> show index from test1\G;
  2. *************************** 1. row ***************************
  3. Table: test1
  4. Non_unique: 1
  5. Key_name: inx_id_name
  6. Seq_in_index: 1
  7. Column_name: name
  8. Collation: A
  9. Cardinality: 552589
  10. Sub_part: NULL
  11. Packed: NULL
  12. Null: YES
  13. Index_type: BTREE
  14. Comment:
  15. Index_comment:
  16. *************************** 2. row ***************************
  17. Table: test1
  18. Non_unique: 1
  19. Key_name: inx_id_name
  20. Seq_in_index: 2
  21. Column_name: id
  22. Collation: A
  23. Cardinality: 567855
  24. Sub_part: NULL
  25. Packed: NULL
  26. Null:
  27. Index_type: BTREE
  28. Comment:
  29. Index_comment:
  30. 2 rows in set (0.00 sec)
  31.  
  32. ERROR:
  33. No query specified
  34.  
  35. mysql>

从上面可以发现只有name和id列上面有索引。来看如下的执行计划。

  1. mysql> explain extended select * from test1 where name='name100' or dept='dept100';
  2. +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
  3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  4. +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
  5. | 1 | SIMPLE | test1 | NULL | ALL | inx_id_name | NULL | NULL | NULL | 769014 | 19.00 | Using where |
  6. +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
  7. 1 row in set, 2 warnings (0.00 sec)
  8.  
  9. mysql>

16)如果将要使用的索引列不是复合索引列表中的第一部分,则不会使用索引

如下例子:可见虽然在id上面建有复合索引,但是由于id不是索引的第一列,那么在查询中这个索引也不会被MySQL采用。

  1. mysql> explain select * from test1 where id=1;
  2. +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
  3. | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
  4. +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
  5. | 1 | SIMPLE | test1 | NULL | ALL | NULL | NULL | NULL | NULL | 787947 | 10.00 | Using where |
  6. +----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+-------------+
  7. 1 row in set, 1 warning (0.00 sec)
  8.  
  9. mysql>

17)如果like是以%开始,可见虽然在name上面建有索引,但是由于where 条件中like的值的“%”在第一位了,那么MySQL也会采用这个索引。

如果WHERE子句的查询条件里使用了比较操作符LIKE和REGEXP,MYSQL只有在搜索模板的第一个字符不是通配符的情况下才能使用索引。比如说,如果查询条件是LIKE 'abc%',MYSQL将使用索引;如果条件是LIKE '%abc',MYSQL将不使用索引。

18)独立的列(对列变量需要计算(聚合运算、类型转换等))

独立的列是指索引列不能是表达式的一部分,也不是是函数的参数。例如以下两个查询无法使用索引:

1)表达式:  select actor_id from sakila.actor where actor_id+1=5;

2)函数参数:select ... where TO_DAYS(CURRENT_DATE) - TO_DAYS(date_col)<=10;应该把列计算转换成常量计算。

示例:

如果列类型是字符串,但在查询时把一个数值型常量赋值给了一个字符型的列名name,那么虽然在name列上有索引,但是也没有用到。

  1. mysql> explain select * from company2 where name=294\G
  2. *************************** 1. row ***************************
  3. id: 1
  4. select_type: SIMPLE
  5. table: company2
  6. type: ALL
  7. possible_keys: ind_company2_name
  8. key: NULL
  9. key_len: NULL
  10. ref: NULL
  11. rows: 1000
  12. Extra: Using where
  13. 1 row in set (0.00 sec)

而下面的sql语句就可以正确使用索引。

  1. mysql> explain select * from company2 where name name=‘294'\G
  2. *************************** 1. row ***************************
  3. id: 1
  4. select_type: SIMPLE
  5. table: company2
  6. type: ref
  7. possible_keys: ind_company2_name
  8. key: ind_company2_name
  9. key_len: 23
  10. ref: const
  11. rows: 1
  12. Extra: Using where
  13. 1 row in set (0.00 sec)

19).在JOIN操作中(需要从多个数据表提取数据时),MYSQL只有在主键和外键的数据类型相同时才能使用索引,否则即使建立了 索引也不会使用

20).在ORDER BY操作中,MYSQL只有在排序条件不是一个查询条件表达式的情况下才使用索引。尽管如此,在涉及多个数据表的查询里,即使有索引可用,那些索引在加快ORDER BY操作方面也没什么作用。

21).不要给“性别”增加索引。如果某个数据列里包含着许多重复的值,就算为它建立了索引也不会有很好的效果。比如说,如果某个数据列里包含了净是些诸如“0/1”或“Y/N”等值,就没有必要为它创建一个索引。

简单的说吧,不需要,因为性别,就两个值男与女(人妖不算,呵)。为这两个值建立索引是不值得的,因为无论多少条记录,建立性别的索引,最多让你的语句少检索一半。但与建立索引带来的损失比,捡芝麻丢西瓜。(可能不准确,但大意如些)。

打个比方,数据库就好比一本新华字典,我们查数据时,可以根据拼音来查,字在字典的排序是根据拼音来排序的,我们要查一个字,可以根据拼音很快就能查到我们要查的字,这就叫作聚集索引!换句话说,聚集索引就是按照物理排序的,也因为是按物理排序的,所以一张表只能有一个聚集索引,也是最快的索引。当然,我们也可以根据部首来查,但是这种查询必须先查找到部首,然后再到检索表查到那么字,最后才能查到我们需要的字,你没办法像拼音查法一样翻翻字典就可以查到,这就叫作普通索引。普通索引可以有多个。

假如一本字典里全是"男"和"女"两个字,那么在检索表里也有很多个"男"和"女",这对查询帮助不大。

22).如果对大的文本进行搜索,使用全文索引而不使用like“%...%”.

23).如果列名是索引,使用column_name is null将使用索引。

如下

  1. mysql> explain select * from company2 where name is null\G
  2. *************************** 1. row ***************************
  3. id: 1
  4. select_type: SIMPLE
  5. table: company2
  6. type: ref
  7. possible_keys: ind_company2_name
  8. key: ind_company2_name
  9. key_len: 11
  10. ref: const
  11. rows: 1
  12. Extra: Using where
  13. 1 row in set (0.00 sec)

24).不使用NOT IN和<>操作
NOT IN和<>操作都不会使用索引将进行全表扫描。NOT IN可以NOT EXISTS代替,id<>3则可使用id>3 or id<3来代替。

25).排序的索引问题
mysql查询只使用一个索引,因此如果where子句中已经使用了索引的话,那么order by中的列是不会使用索引的。因此数据库默认排序可以符合要求的情况下不要使用排序操作;尽量不要包含多个列的排序,如果需要最好给这些列创建复合索引。

26).使用短索引
对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。

27).索引不会包含有NULL值的列
只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。

28).使用ENUM而不是字符串

ENUM保存的是TINYINT,别在枚举中搞一些“中国”“北京”“技术部”这样的字符串,字符串空间又大,效率又低。

三、索引分析方法

3.1查看索引使用情况

如果索引正在工作,Handler_read_key的值将很高,这个值代表了一个行被索引值读的次数。

Handler_read_rnd_next的值高则意味着查询运行低效,并且应该建立索引补救。

  1. mysql> show status like 'Handler_read%';
  2. +-----------------------+--------+
  3. | Variable_name | Value |
  4. +-----------------------+--------+
  5. | Handler_read_first | 9 |
  6. | Handler_read_key | 16 |
  7. | Handler_read_last | 0 |
  8. | Handler_read_next | 680908 |
  9. | Handler_read_prev | 0 |
  10. | Handler_read_rnd | 0 |
  11. | Handler_read_rnd_next | 935519 |
  12. +-----------------------+--------+
  13. 7 rows in set (0.00 sec)
  14.  
  15. mysql>

3.2两个简单实用的优化方法:

分析表的语法如下:(检查一个或多个表是否有错误)

  1. mysql> CHECK TABLE tbl_name[,tbl_name] …[option] option =
  2. { QUICK | FAST | MEDIUM| EXTENDED | CHANGED}
  3. mysql> check table sales;
  4. +--------------+-------+----------+----------+
  5. | Table | Op | Msg_type | Msg_text |
  6. +--------------+-------+----------+----------+
  7. | sakila.sales | check | status | OK |
  8. +--------------+-------+----------+----------+
  9. 1 row in set (0.01 sec)

优化表的语法格式:

OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [,tbl_name]
如果已经删除了表的一大部分,或者如果已经对含有可变长度行的表进行了很多的改动,则需要做定期优化。这个命令可以将表中的空间碎片进行合并,但是此命令只对MyISAM、BDB和InnoDB表起作用。

  1. mysql> optimize table sales;
  2. +--------------+----------+----------+----------+
  3. | Table | Op | Msg_type | Msg_text |
  4. +--------------+----------+----------+----------+
  5. | sakila.sales | optimize | status | OK |
  6. +--------------+----------+----------+----------+
  7. 1 row in set (0.05 sec)

mysql索引之三:索引使用注意规则(索引失效--存在索引但不使用索引)*的更多相关文章

  1. mysql 通过测试'for update',深入了解行锁、表锁、索引

    mysql 通过测试'for update',深入了解行锁.表锁.索引 条件 FOR UPDATE 仅适用于InnoDB存储引擎,且必须在事务区块(BEGIN/COMMIT)中才能生效. mysql默 ...

  2. 《MySQL实战45讲》学习笔记3——InnoDB为什么采用B+树结构实现索引

    索引的作用是提高查询效率,其实现方式有很多种,常见的索引模型有哈希表.有序列表.搜索树等. 哈希表 一种以key-value键值对的方式存储数据的结构,通过指定的key可以找到对应的value. 哈希 ...

  3. mysql查询优化之三:查询优化器提示(hint)

    目录: <MySQL中的两种临时表>--强制使用临时表 SQL_BUFFER_RESULT <MySQL 多表关联更新及删除> <mysql查询优化之三:查询优化器提示( ...

  4. mysql中对字符集和校对规则的认识

    字符集:指符号和字符编码的集合.校对规则:比较字符编码的方式.GBK2312:主要包括简体中文字符及常用符号,对于中文字符采用双字节编码的格式,也就是说一个汉字字符在存储占两个字节.GBK:包括有中. ...

  5. mysql分区表之三:MySQL分区建索引[转]

    介绍 mysql分区后每个分区成了独立的文件,虽然从逻辑上还是一张表其实已经分成了多张独立的表,从“information_schema.INNODB_SYS_TABLES”系统表可以看到每个分区都存 ...

  6. mysql处理存在则更新,不存在则插入(多列唯一索引)

    mysql处理某个唯一索引时存在则更新,不存在则插入的情况应该是很常见的,网上也有很多类似的文章,我今天就讲讲当这个唯一的索引是多列唯一索引时可能会遇到的问题和方法. 方法一: 使用 INSERT I ...

  7. mysql 索引学习--多条件等值查询,顺序不同也能应用联合索引啦

    以前学习这一块的时候,是说:假设建立了联合索引a+b,那么查询语句也一定要是这个顺序才能应用该索引. 那么实际是怎样呢,经过mysql这么多次版本升级,相信mysql已经给我们做了某些优化. 下面是我 ...

  8. Mysql大概1700W大表删除1000W左右数据,发现数据大小和索引大小并没有减少思考

    MySQL删除操作其实是假删除 因为近期在重构优化一个业务的时候 发现有一张表(send_log)数据量将近1700W 左右  占用数据大小17G,索引18G左右  而我们的核心应用在使用的时候 会去 ...

  9. 2020-06-07:mysql中varchar类型的id,where id=1,会用到索引吗?int 类型的id,where id="1",会用到索引吗?为什么?

    福哥答案2020-06-07: 答案来自群员:对于int类型id,查询的varchar 类型 ‘1’会隐式转换成 1,‘1’和 1都能正常走索引:对于varchar类型id,查询的int 类型 1不会 ...

随机推荐

  1. ipynb to pdf

    Q: 如何把jupyter notebook 转为 pdf 文档? A: 尝试了几种python包, 结果都没有成功. 包括: xhtml2pdf, 查看官方的介绍说用pandoc也是一种方法, 但是 ...

  2. Java SSM框架之MyBatis3(三)Mybatis分页插件PageHelper

    引言 对于使用Mybatis时,最头痛的就是写分页,需要先写一个查询count的select语句,然后再写一个真正分页查询的语句,当查询条件多了之后,会发现真不想花双倍的时间写count和select ...

  3. 关于JavaScript代码的执行效率总结

    Javascript是一门非常灵活的语言,我们可以随心所欲的书写各种风格的代码,不同风格的代码也必然也会导致执行效率的差异,开发过程中零零散散地接触到许多提高代码性能的方法,整理一下平时比较常见并且容 ...

  4. opencv的基本数据结构(二)(转)

    转自:原文链接,以下代码.图片.内容有点改动,只为转载不降低博客内容的可阅性,版权归原作者所有. OpenCV中强大的Mat类型大家已经比较熟悉了.这里梳理一些在工程中其他经常用到的几种基本数据类型. ...

  5. 【leetcode 简单】 第八十二题 反转字符串

    编写一个函数,其作用是将输入的字符串反转过来. 示例 1: 输入: "hello" 输出: "olleh" 示例 2: 输入: "A man, a p ...

  6. Python标准库内置函数complex介绍

    from:http://www.jb51.net/article/57798.htm 本函数可以使用参数real + imag*j方式创建一个复数.也可以转换一个字符串的数字为复数:或者转换一个数字为 ...

  7. Python构造方法、析构方法和单例模式

    一.__init__()方法 __init__()通常在初始化一个类实例的时候调用,如: class Student(object): def __init__(self,name,age): sel ...

  8. 非极大值抑制(NMS,Non-Maximum Suppression)的原理与代码详解

    1.NMS的原理 NMS(Non-Maximum Suppression)算法本质是搜索局部极大值,抑制非极大值元素.NMS就是需要根据score矩阵和region的坐标信息,从中找到置信度比较高的b ...

  9. mysql -> 简介&体系结构_01

    数据库简介 数据库,简而言之可视为电子化的文件柜——存储电子文件的处所,用户可以对文件中的数据运行新增.截取.更新.删除等操作. 所谓“数据库”系以一定方式储存在一起.能予多个用户共享.具有尽可能小的 ...

  10. Python2和Python3同时安装到Windows

    上月已经把Python2安装好了,安装目录和及其下的Scripts也在安装时添加到了环境变量PATH中,可以使用python命令执行程序. 安装包:python-2.7.14.amd64.msi(没有 ...