MySQL与SQL优化

文章较长

文章目录

  • MySQL 数据库 -SQL 优化
    • 1.结构图
    • 2. MySQL 数据库引擎简介
      • 2.1 ISAM (Indexed Sequential Access Method)
      • 2.2 MyISAM
      • 2.3 InnoDB
        • 2.3.1 innodb 与 myisam 区别
        • 2.3.2 如何选择
      • 2.4 Memory 存储引擎
      • 2.5 NDBCluster
      • 2.6 Merge存储引擎
      • 2.7 FEDERATED
      • 2.8 ARCHIVE
      • 2.9 BLACKHOLE
      • 2.10 CSV
    • 3. 存储引擎管理
      • 3.1 查看数据库支持的存储引擎
      • 3.2 查看数据库当前使用的存储引擎
      • 3.3 查看数据库表所用的存储引擎
      • 3.4 创建表指定存储引擎
      • 3.5 修改表的存储引擎
      • 3.6 修改默认的存储引擎
    • 4. MySQL 中的索引简介
      • 4.1 索引的优点
      • 4.2 索引的缺点
      • 4.3 什么样的字段适合创建索引
      • 4.4 什么样的字段不适合创建索引:
    • 5. MySQL 中的索引种类
      • 5.1 B-Tree 索引
      • 5.2 Full-text 索引
    • 6. MySQL 中的索引管理
      • 6.1 普通索引
        • 6.1.1 创建索引
        • 6.1.2 查看索引
        • 6.1.3 删除索引
      • 6.2 唯一索引
        • 6.2.1 创建索引
      • 6.3全文索引(FULLTEXT)
        • 6.3.1 创建索引
      • 6.4组合索引(最左前缀)
        • 6.4.1 创建索引
    • 7. MySQL 中的索引优化
      • 7.1 索引不会包含有 NULL 值的列
      • 7.2 使用短索引
      • 7.3 索引列排序
      • 7.4 like语句操作
      • 7.5 不要在列上进行运算
    • 8. 索引总结
    • 9. MySQL 中的 SQL 的常见优化策略
      • 9.1 避免全表扫描
      • 9.2 避免判断 null 值
      • 9.3 避免不等值判断
      • 9.4 避免使用 or 逻辑
      • 9.5 慎用 in 和 notin 逻辑
      • 9.6 注意模糊查询
      • 9.7 避免查询条件中字段计算
      • 9.8 避免查询条件中对字段进行函数操作
      • 9.9 WHERE 子句“=”左边注意点
      • 9.10 组合索引使用
      • 9.11 不要定义无异议的查询
      • 9.12 exists
      • 9.13 索引也可能失效
      • 9.14 表格字段类型选择
      • 9.15 查询语法中的字段
      • 9.16 索引无关优化

MySQL 数据库 -SQL 优化

        MySQL DBMS - MySQL Database Management System。数据库管理系统。

1.结构图

MySQL与SQL优化_第1张图片

2. MySQL 数据库引擎简介

2.1 ISAM (Indexed Sequential Access Method)

        ISAM 是一个定义明确且历经时间考验的数据表格管理方法,它在设计之时就考虑到数 据库被查询的次数要远大于更新的次数。因此,ISAM 执行读取操作的速度很快,而且不占 用大量的内存和存储资源。ISAM 的两个主要不足之处在于,它不支持事务处理,也不能够容错。如果你的硬盘崩溃了,那么数据文件就无法恢复了。如果你正在把 ISAM 用在关键任 务应用程序里,那就必须经常备份你所有的实时数据,通过其复制特性,MYSQL 能够支持 这样的备份应用程序。
注意: 使用ISAM注意点:必须经常备份所有实时数据

2.2 MyISAM

        MyISAM 是 MySQL 的 ISAM 扩展格式(MySQL5.5 之前版本的缺省数据库引擎)数据库 引擎。除了提供 ISAM 里所没有的索引和字段管理的大量功能,MyISAM 还使用一种表格锁 定的机制,来优化多个并发的读写操作,其代价是你需要经常运行 PTIMIZETABLE 命令, 来恢复被更新机制所浪费的空间。MyISAM 还有一些有用的扩展,例如用来修复数据库文件 的 MyISAMCHK 工具和用来恢复浪费空间的 MyISAMPACK 工具。MYISAM 强调了快速读取操作,这可能就是为什么 MySQL 受到了WEB开发如此青睐的主要原因:在 WEB 开发中你所进行的大量数据操作都是读取操作。所以,大多数虚拟主机提供商和 INTERNET 平台提供商 只允许使用 MYISAM 格式。MyISAM格式的一个重要缺陷就是不能在表损坏后恢复数据 。(也不支持事务)
    MyISAM 引擎使用注意:必须经常使用 OptimizeTable 命令清理空间;必须经常备份所 有实时数据。工具有用来修复数据库文件的 MyISAMCHK 工具和用来恢复浪费空间的MyISAMPACK 工具。不支持事务。数据越多,写操作效率越低。因为要维护数据和索 引信息 。(因为要维护数据和索引信息,索引列越多,相对效率越低)
        如果使用该数据库引擎,会生成三个文件:
                .frm:表结构信息
                .MYD:数据文件
                .MYI:表的索引信息

2.3 InnoDB

        InnoDB 数据库引擎都是造就 MySQL 灵活性的技术的直接产品,这项技术就是 MYSQL++ API。在使用 MYSQL 的时候,你所面对的每一个挑战几乎都源于 ISAM 和 MyISAM 数据库引擎不支持事务处理(transactionprocess)也不支持外键。尽管要比 ISAM 和 MyISAM 引擎慢很多,但是 InnoDB 包括了对事务处理和外键的支持,这两点都是前两个引擎所没有的。 是现在的 MySQL(5.5 以上版本)常用版本默认引擎 MySQL 官方对 InnoDB 是这样解释的:InnoDB 给 MySQL 提供了具有提交、回滚和崩溃恢复能力的事务安全(ACID 兼容)存储引擎。InnoDB 锁定在行级并且也在 SELECT 语句提 供一个 Oracle 风格一致的非锁定读,这些特色增加了多用户部署的性能。没有在 InnoDB 中 扩大锁定的需要,因为在 InnoDB 中行级锁定适合非常小的空间。 InnoDB 也支持 FOREIGNKEY 强制。在 SQL 查询中,你可以自由地将 InnoDB 类型的表与其它 MySQL 的表的类型混合起来,甚至在同一个查询中也可以混合。
        InnoDB 是为处理巨大数据量时的最大性能设计,它的 CPU 效率可能是任何其它基于 磁盘的关系数据库引擎所不能匹敌的。 InnoDB 存储引擎被完全与 MySQL 服务器整合, InnoDB 存储引擎为在主内存中缓存数据 和索引而维持它自己的缓冲池。InnoDB 存储它的表&索引在一个表空间中,表空间可以包含数个文件(或原始磁盘分区)。这与 MyISAM 表不同,比如在 MyISAM 表中每个表被存在 分离的文件中。InnoDB 表可以是任何尺寸,即使在文件尺寸被限制为 2GB 的操作系统上。
        在 MySQL5.7 版本中,InnoDB 存储引擎管理的数据文件为两个:分别是 frm,idb 文件。(默认数据库引擎)
        InnoDB 特 点 :
        1. 支 持 事 务
        2. 数 据 多 版 本 读 取 ( InnoDB+MyISAM+ISAM)
        3. 锁 定 机 制 的 改 进
        4 . 实现外键

2.3.1 innodb 与 myisam 区别

  1. InnoDB 支持事务,MyISAM 不支持,对于 InnoDB 每一条 SQL 语言都默认封装成事务, 自动提交,这样会影响速度,所以最好把多条 SQL 语言放在 begin transaction 和 commit 之间,组成一个事务
  2. InnoDB 支持外键,而 MyISAM 不支持。对一个包含外键的 InnoDB 表转为 MYISAM 会失败
  3. InnoDB 是聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引 效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。而 MyISAM 是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的
  4. InnoDB 不保存表的具体行数,执行 select count(*) from table 时需要全表扫描。而 MyISAM 用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快
  5. Innodb 不支持全文索引,而 MyISAM 支持全文索引,查询效率上 MyISAM 要高

2.3.2 如何选择

  1. 是否要支持事务,如果要请选择 innodb,如果不需要可以考虑 MyISAM
  2. 如果表中绝大多数都只是读查询,可以考虑 MyISAM,如果既有读写也挺频繁,请使 用 InnoDB。
  3. 系统崩溃后,MyISAM 恢复起来更困难,能否接受;
  4. MySQL5.5 版本开始 Innodb 已经成为 Mysql 的默认引擎(之前是 MyISAM),说明其优势 是有目共睹的,如果你不知道用什么,那就用 InnoDB,至少不会差。

2.4 Memory 存储引擎

        Memory 存储引擎,通过名字就很容易让人知道,他是一个将数据存储在内存中的存储引擎。Memory 存储引擎不会将任何数据存放到磁盘上,仅仅存放了一个表结构相关信息 的.frm 文件在磁盘上面。所以一旦 MySQL Crash 或者主机 Crash 之后,Memory 的表就只剩下一个结构了。Memory 表支持索引(不支持事务),并且同时支持 Hash 和 B-Tree 两种格式的索引。由于是存放在内存中,所以 Memory 都是按照定长的空间来存储数据的,而且不支持 BLOB 和 TEXT 类型的字段。Memory 存储引擎实现页级锁定。

2.5 NDBCluster

        存储引擎NDB存储引擎也叫NDBCluster存储引擎,主要用于MySQLCluster分布式集群环境,Cluster是MySQL从5.0版本才开始提供的新功能。

2.6 Merge存储引擎

        MERGE存储引擎,在MySQL用户手册中也提到了,也被大家认识为MRG_MyISAM
引擎。Why?因为MERGE存储引擎可以简单的理解为其功能就是实现了对结构相同的MyISAM表,通过一些特殊的包装对外提供一个单一的访问入口,以达到减小应用的复杂度的目的。要创建MERGE表,不仅仅基表的结构要完全一致,包括字段的顺序,基表的索引也必须完全一致。BDB存储引擎BDB存储引擎全称为BerkeleyDB存储引擎,和Innodb一样,也不是MySQL自己开发实现的一个存储引擎,而是由SleepycatSoftware所提供,当然,也是开源存储引擎,同样支持事务安全。

2.7 FEDERATED

        存储引擎FEDERATED存储引擎所实现的功能,和Oracle的DBLINK基本相似,主要用来提供对远程MySQL服务器上面的数据的访问接口。如果我们使用源码编译来安装MySQL,那么必须手工指定启用FEDERATED存储引擎才行,因为MySQL默认是不起用该存储引擎的。

2.8 ARCHIVE

        存储引擎ARCHIVE存储引擎主要用于通过较小的存储空间来存放过期的很少访问的历史数据。
ARCHIVE表不支持索引,通过一个.frm的结构定义文件,一个.ARZ的数据压缩文件还有一
个.ARM的meta信息文件。由于其所存放的数据的特殊性,ARCHIVE表不支持删除,修改操作,仅支持插入和查询操作。锁定机制为行级锁定。

2.9 BLACKHOLE

        存储引擎BLACKHOLE存储引擎是一个非常有意思的存储引擎,功能恰如其名,就是一个“黑洞”。就像我们unix系统下面的“/dev/null”设备一样,不管我们写入任何信息,都是有去无回。

2.10 CSV

        存储引擎CSV存储引擎实际上操作的就是一个标准的CSV文件,它不支持索引。起主要用途就是大家有些时候可能会需要通过数据库中的数据导出成一份报表文件,而CSV文件是很多软件都支持的一种较为标准的格式,所以我们可以通过先在数据库中建立一张CSV表,然后将生成的报表信息插入到该表,即可得到一份CSV报表文件了。

3. 存储引擎管理

3.1 查看数据库支持的存储引擎

mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                        | Transactions | XA   | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| FEDERATED          | NO      | Federated MySQL storage engine                                 | NULL         | NULL | NULL       |
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                          | NO           | NO   | NO         |
| MyISAM             | YES     | MyISAM storage engine                                          | NO           | NO   | NO         |
| BLACKHOLE          | YES     | /dev/null storage engine (anything you write to it disappears) | NO           | NO   | NO         |
| CSV                | YES     | CSV storage engine                                             | NO           | NO   | NO         |
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables      | NO           | NO   | NO         |
| ARCHIVE            | YES     | Archive storage engine                                         | NO           | NO   | NO         |
| InnoDB             | DEFAULT | Supports transactions, row-level locking, and foreign keys     | YES          | YES  | YES        |
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                             | NO           | NO   | NO         |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+

3.2 查看数据库当前使用的存储引擎

mysql> show variables like '%storage_engine%';
+------------------------+--------+
| Variable_name          | Value  |
+------------------------+--------+
| default_storage_engine | InnoDB |
| storage_engine         | InnoDB |
+------------------------+--------+

也可以在 MySQL 配置文件中查看

  • windows - my.ini
  • Linux - my.cnf

3.3 查看数据库表所用的存储引擎

show create table 表名;

mysql> show create table t_user;
+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table  | Create Table                                                                                                                                                                                                              |
+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t_user | CREATE TABLE `t_user` (
  `uid` int(11) NOT NULL AUTO_INCREMENT,
  `uname` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 |
+--------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

3.4 创建表指定存储引擎

create table table_name (column_name column_type) engine = engine_name

mysql> create table t_temp (id int(11) primary key,name varchar(255)) engine=myisam;
Query OK, 0 rows affected (0.07 sec)
mysql> show create table t_temp;
+--------+------------------------------------------------------------------------------------------------------------------------------------------------+
| Table  | Create Table                                                                                                                                   |
+--------+------------------------------------------------------------------------------------------------------------------------------------------------+
| t_temp | CREATE TABLE `t_temp` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 |
+--------+------------------------------------------------------------------------------------------------------------------------------------------------+

3.5 修改表的存储引擎

alter table table_name engine=engine_name

mysql> alter table t_temp engine = innodb;
Query OK, 0 rows affected (0.11 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> show create table t_temp;
+--------+------------------------------------------------------------------------------------------------------------------------------------------------+
| Table  | Create Table                                                                                                                                   |
+--------+------------------------------------------------------------------------------------------------------------------------------------------------+
| t_temp | CREATE TABLE `t_temp` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+--------+------------------------------------------------------------------------------------------------------------------------------------------------+

3.6 修改默认的存储引擎

在MySQL 配置文件中修改下述内容:
        default-storage-engine=INNODB
MySQL 配置文件:

  • windows 系统 - MySQL 安装目录/my.ini (5.7 版本 my.ini 文件在数据目录中。C:/programdata/MySQLServer5.7/mysql/)
  • linux 系统 -/etc/my.cnf

重启MySQL数据库

4. MySQL 中的索引简介

4.1 索引的优点

为什么要创建索引?这是因为,创建索引可以大大提高系统的查询性能。

  1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
  2. 可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
  3. 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
  4. 在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
  5. 通过使用索引,可以在查询的过程中,使用查询优化器,提高系统的性能。

4.2 索引的缺点

        也许会有人要问:增加索引有如此多的优点,为什么不对表中的每一个列创建一个索 引呢?这种想法固然有其合理性,然而也有其片面性。虽然,索引有许多优点, 但是,为 表中的每一个列都增加索引,是非常不明智的。 这是因为,增加索引也有许多不利的一个方面:

  1. 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
  2. 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间。如果要建立聚簇索引,那么需要的空间就会更大。
  3. 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。

4.3 什么样的字段适合创建索引

        索引是建立在数据库表中的某些列的上面。因此,在创建索引的时候,应该仔细考虑在哪些列上可以创建索引,在哪些列上不能创建索引。 一般来说,应该在具备下述特性的 列上创建索引:

  1. 在经常需要搜索的列上,可以加快搜索的速度;
  2. 在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
  3. 在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
  4. 在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
  5. 在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
  6. 在经常使用在 WHERE 子句中的列上面创建索引,加快条件的判断速度。 建立索引,一般按照 select 的 where 条件来建立,比如: select 的条件是 where f1 and f2,那么如果我们在字段 f1 或字段 f2 上建立索引是没有用的,只有在字段 f1 和 f2 上同时建立索引才有用等。

4.4 什么样的字段不适合创建索引:

        同样,对于有些列不应该创建索引。一般来说,不应该创建索引的这些列具有下述特点:

  1. 对于那些在查询中很少使用或者参考的列不应该创建索引。这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
  2. 对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例, 即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
  3. 对于那些定义为 text,image 和 bit 数据类型的列不应该增加索引。这是因为这些列的数据量要么相当大,要么取值很少。
  4. 当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。

5. MySQL 中的索引种类

5.1 B-Tree 索引

        B-Tree 索引,顾名思义,就是所有的索引节点都按照 balance tree 的数据结构来存储。
        B-tree 结构可以显著减少定位记录时所经历的中间过程,从而加快存取速度。 B-tree 中,每个结点包含:

  1. 本结点所含关键字的个数;
  2. 指向父结点的指针;
  3. 关键字;
  4. 指向子结点的指针;

        对于一棵 m 阶 B-tree,每个结点至多可以拥有 m 个子结点。各结点的关键字和可以拥 有的子结点数都有限制,规定 m 阶 B-tree 中,根结点至少有 2 个子结点,除非根结点为叶 子节点,相应的,根结点中关键字的个数为 1~m-1;非根结点至少有[m/2]([],向上取整) 个子结点,相应的,关键字个数为[m/2]-1~m-1。
B-tree 有以下特性:

  1. 关键字集合分布在整棵树中;
  2. 任何一个关键字出现且只出现在一个结点中;
  3. 搜索有可能在非叶子结点结束;
  4. 其搜索性能等价于在关键字全集内做一次二分查找;
  5. 自动层次控制;

由于限制了除根结点以外的非叶子结点,至少含有 M/2 个儿子,确保了结点的至少利用率,其最低搜索性能为:
MySQL与SQL优化_第2张图片
        其中,M 为设定的非叶子结点最多子树个数,N 为关键字总数; 所以 B-树的性能总是等价于二分查找(与 M 值无关) ,也就没有 B 树平衡的问题; 由于 M/2 的限制,在插入结点时,如果结点已满,需要将结点分裂为两个各占 M/2 的 结点;删除结点时,需将两个不足 M/2 的兄弟结点合并。

5.2 Full-text 索引

        Full-text 索引就是我们常说的全文索引,他的存储结构也是 b-tree。主要是为了解决在我们需要用 like 查询的低效问题。只能解决’xxx%’的 like 查询。
        如:字段数据为 ABCDE,索引建立为 - A、AB、ABC、ABCD、ABCDE 五个。

6. MySQL 中的索引管理

        在 MySQL 中,对索引的查看和删除操作是所有索引类型通用的。

6.1 普通索引

        这是最基本的索引,它没有任何限制 MyIASM 中默认的 BTREE 类型的索引,也是我们大多数情况下用到的索引。

6.1.1 创建索引

  • CREATE INDEX index_name ON table_name(column(length))

  • ALTER TABLE table_name ADD INDEX index_name(column(length))

  • CREATE TABLE table_name (id int not null auto_increment,title varchar(30) ,PRIMARY KEY(id),INDEX index_name(title(5)))

6.1.2 查看索引

  • SHOW INDEX FROM [table_name] SHOW KEYS FROM [table_name] # 只在 MySQL 中可以使用 keys 关键字。

6.1.3 删除索引

  • DROP INDEX index_name ON talbe_name
  • ALTER TABLE table_name DROP INDEX index_name
  • ALTER TABLE table_name DROP PRIMARY KEY

6.2 唯一索引

        与普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值(注意和主键不同)。 如果是组合索引,则列值的组合必须唯一,创建方法和普通索引类似

6.2.1 创建索引

  • CREATEUNIQUEINDEXindex_name ONtable_name(column(length))
  • ALTERTABLEtable_nameADDUNIQUEindex_name (column(length))
  • CREATE TABLE table_name (id int not null auto_increment,title varchar(30) ,PRIMARY KEY(id), UNIQUE index_name(title(length)))

6.3全文索引(FULLTEXT)

        MySQL 从 3.23.23 版开始支持全文索引和全文检索,FULLTEXT索引仅可用于MyISAM表 ;他们可以从 CHAR 、 VARCHAR或 TEXT列 中作为 CREATETABLE 语句的一部分被创建,或 是随后使用 ALTERTABLE 或 CREATEINDEX 被添加。
        对于较大的数据集,将你的资料输入一个没有 FULLTEXT 索引的表中,然后创建索引, 其速度比把资料输入现有 FULLTEXT 索引的速度更为快。不过切记对于大容量的数据表,生 成全文索引是一个非常消耗时间非常消耗硬盘空间的做法。

6.3.1 创建索引

  • CREATE FULLTEXT INDEX index_name ON table_name(column(length))
  • ALTER TABLE table_name ADD FULLTEXT index_name(column)
  • CREATE TABLE table_name (id int not null auto_increment,title varchar(30) ,PRIMARY KEY(id), FULLTEXT index_name(title))

6.4组合索引(最左前缀)

        CREATE TABLE article(id int not null,title varchar(255) , timedate);
        平时用的 SQL 查询语句一般都有比较多的限制条件,所以为了进一步榨取 MySQL 的效 率,就要考虑建立组合索引。例如上表中针对 title 和 time 建立一个组合索引:ALTER TABLE article ADD INDEX index_title_time(title(50),time(10))。建立这样的组合索引,其实是相当于分 别建立了下面两组组合索引:
        –title,time
        –title
        为什么没有 time 这样的组合索引呢?这是因为 MySQL 组合索引“最左前缀”的结果。简 单的理解就是只从最左面的开始组合。并不是只要包含这两列的查询都会用到该组合索引, 如下面的几个 SQL 所示:

  1. 使用到上面的索引
    • SELECT * FROM article WHERE title='测试' AND time=1234567890;
    • SELECT * FROM article WHERE title='测试';
  2. 不使用上面的索引
    • SELECT * FROM article WHERE time=1234567890;

6.4.1 创建索引

CREATE INDEX index_name ON table_name(column_list)

7. MySQL 中的索引优化

        上面都在说使用索引的好处,但过多的使用索引将会造成滥用。因此索引也会有它的缺 点。虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行 INSERT、 UPDATE和 DELETE 次数大于查询次数时,放弃索引。因为更新表时,MySQL 不仅要保存数据,还要 保存一下索引文件。建立索引会占用磁盘空间的索引文件。一般情况这个问题不太严重,但如果你在一个大表上创建了多种组合索引,索引文件的会膨胀很快。索引只是提高效率的一 个因素,如果你的 MySQL 有大数据量的表,就需要花时间研究建立最优秀的索引,或优化 查询语句。

7.1 索引不会包含有 NULL 值的列

        只要列中包含有 NULL 值都将不会被包含在索引中,组合索引中只要有一列含有 NULL 值,那么这一列对于此组合索引就是无效的。所以我们在数据库设计时不要让字段的默认值 为 NULL。create table table_name (c1 varchar(32) default ‘0’ )

7.2 使用短索引

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

7.3 索引列排序

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

7.4 like语句操作

        一般情况下不鼓励使用like操作, 如果非使用不可,如何使用也是一个问题。 like“%aaa%” 不会使用索引,而 like“aaa%”可以使用索引。

7.5 不要在列上进行运算

        例如:select * from users where YEAR(adddate)<2007,将在每个行上进行运算,这将导致索引失效而进行全表扫描 ,因此我们可以改成 : select * from users where adddate<’2007-01-01′

8. 索引总结

        最后总结一下,MySQL 只对以下操作符才使用索引:<,<=,=,>,>=,between,in,以及某些时候的like(不以通配符%或_开头的情形)。而理论上每张表里面最多可创建16个索引,不过除非是数据量真的很多,否则过多的使用索引也不是那么好玩的。 建议:一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。

9. MySQL 中的 SQL 的常见优化策略

9.1 避免全表扫描

        对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 orderby 涉及的列上建立索引。

9.2 避免判断 null 值

        应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:

selec tid from t where num is null

可以在 num 上设置默认值 0,确保表中 num 列没有 null 值,然后这样查询:

select id from t where num = 0

9.3 避免不等值判断

        应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。

9.4 避免使用 or 逻辑

        应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进 行全表扫描,如:

select id from t where num = 10 or num = 20

可以这样查询:

select id from t where num = 10 union all select id from t where num = 20

9.5 慎用 in 和 notin 逻辑

        in 和 notin 也要慎用,否则会导致全表扫描,如:

select id from t1 where num in ( selec tid from t2 where id > 10)

        此时外层查询会全表扫描,不使用索引。可以修改为:

select id from t1,( select id from t1 where id > 10 ) t2 where t1.id = t2.id

        此时索引被使用,可以明显提升查询效率。

9.6 注意模糊查询

        下面的查询也将导致全表扫描:

select id from t where name like '%abc%' 

        模糊查询如果是必要条件时,可以使用

select id from t where name like 'abc%'

        来实现模糊查询,此时索引将被使用。如果头匹配是必要逻辑,建议使用全文搜索引擎(Elasticsearch、 Lucene、Solr 等)。

9.7 避免查询条件中字段计算

        应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进 行全表扫描。如:

 select id from t where num/2=100

应改为:

select id from t where num=100*2

9.8 避免查询条件中对字段进行函数操作

        应尽量避免在 where 子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:

select id from t where substring(name,1,3)='abc'--name

以 abc 开头的 id 应改为:

select id from t where name like 'abc%'

9.9 WHERE 子句“=”左边注意点

        不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统 将可能无法正确使用索引。

9.10 组合索引使用

        在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。

9.11 不要定义无异议的查询

        不要写一些没有意义的查询,如需要生成一个空表结构:

select col1,col2 into #t from t where 1=0

这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:

 create table #t(...)

9.12 exists

很多时候用 exists 代替 in 是一个好的选择:

select num from a where num in(select num from b) 

用下面的语句替换:

select num from a where exists(select 1 from b where num=a.num)

9.13 索引也可能失效

        并不是所有索引对查询都有效,SQL 是根据表中数据来进行查询优化的,当索引列有大 量数据重复时,SQL 查询可能不会去利用索引,如一表中有字段 sex,male、female 几乎各一半,那么即使在 sex 上建了索引也对查询效率起不了作用。

9.14 表格字段类型选择

        尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每 一个字符,而对于数字型而言只需要比较一次就够了。 尽可能的使用 varchar 代替 char ,因为首先可变长度字段存储空间小,可以节省存储 空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

9.15 查询语法中的字段

        任何地方都不要使用 select * from t ,用具体的字段列表代替" * ",不要返回用不到的任何字段。

9.16 索引无关优化

        不使用*、尽量不使用 union,union all 等关键字、尽量不使用 or 关键字、尽量使用等值判断。
表连接建议不超过 5 个。如果超过 5 个,则考虑表格的设计。(互联网应用中)
表连接方式使用外联优于内联。 外连接有基础数据存在。如:A left join B,基础数据是 A。 A inner join B,没有基础数据的,先使用笛卡尔积完成全连接,在根据连接条件得到内 连接结果集。
大数据量级的表格做分页查询时,如果页码数量过大,则使用子查询配合完成分页逻辑。

Select * from table limit 1000000,10

Select * from table where id in(select pk from table limit 100000,10)

end…

你可能感兴趣的:(SQL)