# 数据库优化及索引

如何优化数据库

第一、优化索引、SQL语句、分析慢查询
第二、设计表的时候严格按照数据库的设计范式来设计数据库
第三、我们可以加上redis缓存,将经常被访问到的数据,但是不需要经常变化的数据放入至redis缓存服务器里面,这样的话能够节约太强盘I/0
第四、还可优化硬件,在硬件层面,我们可以使用更好的一些硬盘(固态硬盘),使用一些磁盘阵列技术(raid 0,raid1,raid5)
raid0 最简单的 (两块硬盘硬盘相加100G + 100 G = 200G)
raid1 镜像卷 把同样的数据写两份。可以随机从A/B里面读取,更高。硬盘坏了一块,数据也不会丢失
raid5 3块硬盘,坏了一块,另外两块也能工作。
第五、如果以上都做速度还是慢,先不要去切分可以使用MySQL内部自带的表分区技术,来将数据分成不同的文件。这样能够让磁盘在读取的时候效率更高。
第六、可以再做垂直分表,可以将不经常读数据放到另外一个表里面去。这样能够节约磁盘IO
第七、如果发现我们的效率还是不够高,我们可以采用主从的方式来将数据读写分离。
第八、数据量特别大,我们优化起来会很困难可以使数数据库中间件的方式,将数据进行分库分表分机器。(原理,数据路由)
第九、此外,我们还可以采用一些更快的存储方式,例如NoSQL来存储一些我们需要经常访问到的数据。从数据库里面取出来后,再到NoSQL取出一些其他的数据。
第十、此外还有一些表引擎 选择,参数优化和一些相关小技巧都是优化MySQL的方式
第十一、我们还可以将我们的业务系统在架构级别进行缓存,静态化和分式式。
第十二、不使用全文索引,使用xunsearch,ES或者云服务器上的索引。

如何优化SQL语句—五星重要

1)尽量选择较小的列–需要哪些列就使用哪些列 长度较小的列
2)将where中用的比较频繁的字段建立索引–有多个条件,使用索引的列排在前面
3)select子句中避免使用‘*’
4)避免在索引列上使用计算、not in 和<>等操作
5)当只需要一行数据的时候使用limit 1
6)保证单表数据不超过200W,适时分割表。针对查询较慢的语句,可以使用explain 来分析该语句具体的执行情况。
7)避免改变索引列的类型。
8)选择最有效的表名顺序,from子句中写在最后的表是基础表,将被最先处理,在from子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。
9)避免在索引列上面进行计算。
10)尽量缩小子查询的结果

索引类型

1.普通索引
是最基本的索引,它没有任何限制。它有以下几种创建方式:
(1)直接创建索引

CREATE INDEX index_name ON table(column(length))

(2)修改表结构的方式添加索引

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

2.唯一索引
与前面的普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。它有以下几种创建方式:
(1)创建唯一索引

CREATE UNIQUE INDEX indexName ON table(column(length))
create index index_name on table(name,city,age)

(2)修改表结构

ALTER TABLE table_name ADD UNIQUE indexName ON (column(length))

3.主键索引
是一种特殊的唯一索引,一个表只能有一个主键,不允许有空值。一般是在建表的时候同时创建主键索引:

CREATE TABLE `table` (
    `id` int(11) NOT NULL AUTO_INCREMENT ,
    `title` char(255) NOT NULL ,
    PRIMARY KEY (`id`)
);

4.组合索引
指多个字段上创建的索引,只有在查询条件中使用了创建索引时的第一个字段,索引才会被使用。使用组合索引时遵循最左前缀集合

ALTER TABLE `table` ADD INDEX name_city_age (name,city,age); 
select * from table where age=20  索引未生效
select * from table where city='大连' and age=20   索引未生效
select * from table where name=''
select * from table where name='' and city=''

5.全文索引
主要用来查找文本中的关键字,而不是直接与索引中的值相比较。fulltext索引跟其它索引大不相同,它更像是一个搜索引擎,而不是简单的where语句的参数匹配。fulltext索引配合match against操作使用,而不是一般的where语句加like。它可以在create table,alter table ,create index使用,不过目前只有char、varchar,text 列上可以创建全文索引。值得一提的是,在数据量较大时候,现将数据放入一个没有全局索引的表中,然后再用CREATE index创建fulltext索引,要比先为一张表建立fulltext然后再将数据写入的速度快很多。

索引的存储结构

\1. B-Tree索引

它使用B-Tree数据结构来存储数据,实际上很多存储引擎使用的是B+Tree。B+Tree和B-Tree的不同点在于:

(1) 非叶子节点只存储键值信息

(2) 所有叶子节点之间都有链指针

(3) 数据记录都存放在叶子节点中

B-Tree模型:

img

B+Tree模型:

img

B-Tree对索引列是顺序组织存储的,很适合查找范围数据。看下B-Tree索引适用哪些查询:

(1) 全值匹配

​ 全值匹配是指查询中使用的条件和索引中的所有列进行匹配。比如有索引 index(last_name, first_name, date) ,查询的条件为:where last_name=? and first_name=? and date=? 。

(2) 匹配最左前缀

​ 只使用索引的第一列。比如查询条件为:where last_name = ?

(3) 匹配列前缀

​ 只匹配某一列值得开头部分。

(4) 匹配范围值

(5) 精确匹配某一列并范围匹配另一列

​ 比如:where last_name = ? and first_name like kim%

(6) 只访问索引的查询

\2. 哈希索引

哈希索引基于哈希表实现。哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。在mysql中,Memory引擎显式支持哈希索引。

举例说明,有张表:

CREATE TABLE testhash (

​ fname VARCHAR(50) NOT NULL,

lname VARCHAR(50) NOT NULL,

​ KEY USING HASH(fname)

) ENGINE=MEMORY;

表中有如下数据:

fnamelname
ArjenLentz
BaronSchwartz
PeterZaitsev
VadimTkachenko

假设索引使用假想的哈希函数f(), 如下:

f(‘Arjen’) = 2323

f(‘Baron’) = 7437

f(‘Peter’) = 8784

f(‘Vadim’) = 2458

那么哈希索引的数据结构:

槽(Slot) 值(Value)

2323 指向第1行的指针

2458 指向第4行的指针

7437 指向第2行的指针

8784 指向第3行的指针

如果使用一条sql语句进行查询:select lname from testhash where fname = ‘Peter’; 过程为:

计算‘Peter’的哈希值(f(‘Peter’)=8784)----->查找哈希值对应的指针----->根据指针或得相应的数据。

哈希索引的特点:索引的结构十分紧凑,因此查找速度非常快;哈希索引数据不是按照索引顺序存储的,无法用于排序;哈希索引不支持部分索引列匹配查找;哈希索引只支持等值比较查询(=,IN(),<=>),不支持范围查询,如where price>100;

  1. 全文索引

全文索引查找的是文本中的关键词,不是直接比较索引中的值。

聚簇索引和非聚簇索引

聚簇索引与非聚簇索引是从文件存储的角度进行划分:

聚簇索引:将数据存储与索引放到了一块,找到索引也就找到了数据(InnoDB)
非聚簇索引:将数据和索引进行分开存储(MyISAM)
聚簇索引

一个表仅有一个聚簇索引,默认是主键

聚簇索引性能最好而且具有唯一性,所以非常珍贵,必须慎重设置。一般要根据这个表最常用的SQL查询方式来进行选择,某个字段作为聚簇索引,或组合聚簇索引,这个要看实际情况。

在这里插入图片描述

聚簇索引不是一种索引类型,而是一种数据存储方式。innoDB的聚簇索引实际上在同一个结构中保存了B-Tree索引和数据行。当表有聚簇索引时,它的行数据实际上存放在索引的叶子页中,因为无法同时把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。

优点:

  • 可以把相关数据保存在一起,数据访问就更快。
  • 聚簇索引将索引和数据保存在同一个B-Tree中,因此获取数据比非聚簇索引要更快。
  • 使用聚簇索引扫描的查询可以直接使用页节点中的主键值。

缺点:

  • 聚簇索引最大程度提高了IO密集型应用的性能,如果数据全部在内存中将失去优势。
  • 更新聚簇索引列的代价很高,因为会强制每个被更新的行移动到新位置。
  • 基于聚簇索引的表插入新行或主键被更新导致行移动时,可能导致页分裂,表会占用更多磁盘空间。
  • 当行稀疏或由于页分裂导致数据存储不连续时,全表扫描可能很慢

索引失效

索引查询失效的几个情况:

1、like 以%开头,索引无效;当like前缀没有%,后缀有%时,索引有效。

img

2、or语句前后没有同时使用索引。当or左右查询字段只有一个是索引,该索引失效,只有当or左右查询字段均为索引时,才会生效

img

img

3、组合索引,不是使用第一列索引,索引失效。

img

4、数据类型出现隐式转化。如varchar不加单引号的话可能会自动转换为int型,使索引无效,产生全表扫描。

img

5、在索引列上使用 IS NULL 或 IS NOT NULL操作。索引是不索引空值的,所以这样的操作不能使用索引,可以用其他的办法处理,例如:数字类型,判断大于0,字符串类型设置一个默认值,判断是否等于默认值即可。(此处是错误的!

img

解释以上错误:

此处我将重新创建一个emp表

img

创建新的索引

img

查看索引

img

执行SQL语句

img

img

由此可发现有使用到索引

总结:在索引列上使用 IS NULL 或 IS NOT NULL操作,索引不一定失效!!!

使用联合查询请参考:https://www.jianshu.com/p/3cae3e364946

错误详解请参考:https://mp.weixin.qq.com/s/CEJFsDBizdl0SvugGX7UmQ

6、在索引字段上使用not,<>,!=。不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。 优化方法: key<>0 改为 key>0 or key<0。

img

img

7、对索引字段进行计算操作、字段上使用函数。(索引为 emp(ename,empno,sal))

img

img

8、当全表扫描速度比索引速度快时,mysql会使用全表扫描,此时索引失效。

索引失效分析工具:

可以使用explain命令加在要分析的sql语句前面,在执行结果中查看key这一列的值,如果为NULL,说明没有使用索引。

索引的缺点

1.创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加

2.索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大

3.当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度

  • 25
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值