数据库(二)—— MySQL索引优化 MySQL的索引优化

一、MySQL 5.7的初始化配置

/usr/local/mysql/bin/mysqld --initialize-insecure  --user=mysql --datadir=/opt/mysql/data --basedir=/opt/mysql

二、MySQL配置文件

1、配置

vim /etc/my.cnf
	[mysqld]
	basedir = /opt/mysql
	datadir = /opt/mysql/data
	port = 3306
	user = mysql
	socket = /tmp/mysql.sock
	log_error = /var/log/mysql.log
	[mysql]
	socket=/tmp/mysql.sock

2、配置文件作用

(1)影响服务端的启动

标签:[mysqld]   [mysqld_safe]   [server]   ...
  • 必须配置的内容
[mysqld]
basedir = /opt/mysql
datadir = /opt/mysql/data
user = mysql
socket = /tmp/mysql.sock
port = 3306
server_id = 6

(2)影响客户端的连接

标签:[client]  [mysql]    [mysqldump] ...
  • 配置内容
[mysql]
socket = /tmp/mysql.sock

(3)影响初始化

三、多实例

端口号为3307、3308、3309

1、创建相关的目录

mkdir -p /data/330{7..9}/data

2、创建实例的配置文件

cat>> /data/3307/my.cnf<<EOF
    [mysqld]
    basedir=/opt/mysql              
    datadir=/data/3307/data
    user=mysql
    socket=/data/3307/mysql.sock
    port=3307 
    server_id=3307
    EOF

cp /data/3307/my.cnf /data/3308 
cp /data/3307/my.cnf /data/3309 

sed -i 's#3307#3308#g' /data/3308/my.cnf 
sed -i 's#3307#3309#g' /data/3309/my.cnf 

3、初始化

# 初始化数据 
mysqld --initialize-insecure  --user=mysql --datadir=/data/3307/data --basedir=/opt/mysql
mysqld --initialize-insecure  --user=mysql --datadir=/data/3308/data --basedir=/opt/mysql
mysqld --initialize-insecure  --user=mysql --datadir=/data/3309/data --basedir=/opt/mysql

4、授权

chown -R mysql.mysql /data/*

5、启动实例

mysqld_safe --defaults-file=/data/3307/my.cnf &
mysqld_safe --defaults-file=/data/3308/my.cnf &
mysqld_safe --defaults-file=/data/3309/my.cnf &

6、查看启动状况

netstat -lnp|grep 330

7、测试

mysql -S /data/3307/mysql.sock
mysql -S /data/3308/mysql.sock
mysql -S /data/3309/mysql.sock

8、配置启动脚本

cat >> /etc/systemd/system/mysqld3307.service <<EOF
    [Unit]
    Description=MySQL Server
    Documentation=man:mysqld(8)
    Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
    After=network.target
    After=syslog.target
    [Install]
    WantedBy=multi-user.target
    [Service]
    User=mysql
    Group=mysql
    ExecStart=/opt/mysql/bin/mysqld --defaults-file=/data/3307/my.cnf
    LimitNOFILE = 5000
    EOF

    
cp  /etc/systemd/system/mysqld3307.service   /etc/systemd/system/mysqld3308.service 
cp  /etc/systemd/system/mysqld3307.service   /etc/systemd/system/mysqld3309.service 


sed -i 's#3307#3308#g'   /etc/systemd/system/mysqld3308.service
sed -i 's#3307#3309#g'   /etc/systemd/system/mysqld3309.service

9、开机自启

[root@standby ~]# systemctl start mysqld3307
[root@standby ~]# systemctl start mysqld3308
[root@standby ~]# systemctl start mysqld3309
[root@standby ~]# netstat -lnp|grep 330
tcp6       0      0 :::3307                 :::*                    LISTEN      3773/mysqld         
tcp6       0      0 :::3308                 :::*                    LISTEN      3808/mysqld         
tcp6       0      0 :::3309                 :::*                    LISTEN      3843/mysqld         
tcp6       0      0 :::3306                 :::*                    LISTEN      2721/mysqld         
[root@standby ~]# systemctl stop mysqld3309
[root@standby ~]# systemctl stop mysqld3308
[root@standby ~]# systemctl stop mysqld3307

[root@standby ~]# systemctl enable  mysqld3307
[root@standby ~]# systemctl enable  mysqld3308
[root@standby ~]# systemctl enable  mysqld3309

10、设定mysql密码

mysqladmin -uroot -p password 123

11、忘记密码

# root等用户信息存在mysql.user表中
select user,authentication_string,host from mysql.user;

# 1.停数据库
/etc/init.d/mysqld stop
# 2.启动数据库为无密码验证模式
mysqld_safe --skip-grant-tables --skip-networking  &
update mysql.user set authentication_string=PASSWORD('456') where user='root' and host='localhost';
/etc/init.d/mysqld restart

[root@standby ~]# mysql -uroot -p123
[root@standby ~]# mysql -uroot -p456

四、数据类型

1、整型

int 
最多存10位数字:-2^31 ~ 2^31-1

2、字符串类型

char       定长,存储效率高,但是对于变化多的字段,空间浪费高
varchar    变长,存储时判断长度,存储会有额外开销,按需分配空间
enum       枚举类型

3、时间类型

datetime    日期+时间
date        日期
timestamp   时间戳
time      时间

规范

  • 少于10位数,用 int;大于10位用 char
  • char 和 varchar 选择时,字符长度一定不变用 char ;字符长度改变的用 varchar
    在使用可变的数据类型时,将来使用不同的数据类型,对于索引树的高度会有影响
  • 选择合适的数据类型
  • 合适长度

五、索引

1、索引作用

优化查询,select 查询有三种情况:缓存查询(不在mysql中进行数据查询),全表扫描,索引扫描

2、索引种类

  • Btree(btree b+tree b*tree)

  • Rtree

  • HASH

  • FullText

3、Btree 分类

聚集索引:基于主键,自动生成的,一般是建表时创建主键。如果没有主键,自动选择唯一键做为聚集索引
辅助索引:人为创建的(普通,覆盖)
唯一索引:人为创建(普通索引,聚集索引)

4、聚集索引和辅助索引的对比

  • 聚集索引:叶子结点,按照主键列的顺序,存储的整行数据,就是真正的数据页
  • 辅助索引: 叶子结点,列值排序之后,存储到叶子结点+对应的主键的值,便于回表查询

六、MySQL索引管理

1、创建索引(辅助索引)

alter table blog_blog add key idx_name(name);
# 或者
create index index_name on blog_blog(name);

2、删除索引

alter table blog_blog drop key idx_name(name);
# 或者
drop index index_name on blog_blog(name);

3、查看创建的索引

show index from blog_blog;

4、前缀索引

# select count(*),substring(password,1,20) as sbp  from blog_userinfo group by sbp;
alter table blog_userinfo add index idx(password(10));

5、唯一键索引

alter table blog_blog add unique key uni_name(name);

6、覆盖索引(联合索引)

作用:不需要回表查询,不需要聚集索引,所有的数据都从辅助索引中获取

alter table t1 add index idx_abc(age,box,electric);   # 第一个为主要条件,第一条件,查询量多的条件放前面,有序

# 查询的时候,where后面条件不是age放首位的条件,都不走联合索引

七、explain(desc)命令的应用

获取优化器选择后的执行计划

 oldguo [world]>explain select * from city where countrycode='CHN'G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: city
         type: ref
possible_keys: CountryCode,idx_co_po
          key: CountryCode
      key_len: 3
          ref: const
         rows: 1
        Extra: Using index condition
1 row in set (0.00 sec)

1、字段

(1)type —— 查询类型(上至下性能增加)

  • 判断是全表扫描还是索引扫描(ALL是全表扫描,其他的是索引扫描)

  • 判断是哪一种类的索引扫描
    ALL:全表扫描 —— select * from t1;
    Index:全索引扫描 —— desc select countrycode from city ;

    range:索引范围扫描 —— where > < >= <= in or between and like 'CH'

    select * from city where country in ('China','USA')s
    

    ref:辅助索引等值查询 —— in与or替换为union的查询效率会提高

    select * from city where country='China'
    union all
    select * from city where country='USA'
    

    eq_ref:多表连接查询(join on )

    constsystem :主键或唯一键等值查询

(2)Extra

using filesort:文件排序,可以进行优化

将order by、group by、distinct 后面的列和where条件列建立联合索引

(3)其他字段

possible_keys: CountryCode,idx_co_po      ---->可能会走的索引
key: CountryCode						  ---->真正走的索引
type: ref								  ---->索引类型
Extra: Using index condition              ---->额外信息

八、建立索引规范

1、建表时一定要有主键,如果相关列可以作为主键,做一个无关列

2、选择唯一性索引

唯一性索引的值是唯一的,可以更快速的通过该索引来确定某条记录。

主键索引和唯一键索引,在查询中使用是效率最高的。

注意:如果重复值较多,可以考虑采用联合索引

3、为经常需要排序、分组和联合操作的字段建立索引

经常需要ORDER BY、GROUP BY,join on等操作的字段,排序操作会浪费很多时间。
如果为其建立索引,可以有效地避免排序操作。

4、为常作为where查询条件的字段建立索引

如果某个字段经常用来做查询条件,那么该字段的查询速度会影响整个表的查询速度。因此,
为这样的字段建立索引,可以提高整个表的查询速度。

5、尽量使用前缀来索引
如果索引字段的值很长,最好使用值的前缀来索引。例如,TEXT和BLOG类型的字段,进行全文检索
会很浪费时间。如果只检索字段的前面的若干个字符,这样可以提高检索速度。

6.限制索引的数目
索引的数目不是越多越好。每个索引都需要占用磁盘空间,索引越多,需要的磁盘空间就越大。
修改表时,对索引的重构和更新很麻烦。越多的索引,会使更新表变得很浪费时间。

7.删除不再使用或者很少使用的索引(percona toolkit)
表中的数据被大量更新,或者数据的使用方式被改变后,原有的一些索引可能不再需要。数据库管理
员应当定期找出这些索引,将它们删除,从而减少索引对更新操作的影响。

8.大表加索引,要在业务不繁忙期间操作



九、建立索引原则

(1) 必须要有主键,如果没有可以做为主键条件的列,创建无关列
(2) 经常做为where条件列 order by group by join on的条件(业务:产品功能+用户行为)
(3) 最好使用唯一值多的列作为索引,如果索引列重复值较多,可以考虑使用联合索引
(4) 列值长度较长的索引列,我们建议使用前缀索引.
(5) 降低索引条目,一方面不要创建没用索引,不常使用的索引清理,percona toolkit
(6) 索引维护要避开业务繁忙期

十、不走索引的情况

1、没有查询条件,或者查询条件没有建立索引

2、查询结果集是原表中的大部分数据,应该是25%以上

3、索引本身失效,统计数据不真实

4、查询条件使用函数在索引列上,或者对索引列进行运算,运算包括(+,-,*,/,! 等)

5、隐式转换导致索引失效.这一点应当引起重视,也是开发中经常会犯的错误.

6、<> ,not in 不走索引

7、 like "%_" 百分号在最前面不走

8、单独引用联合索引里非第一位置的索引列.作为条件查询时不走索引.

十一、压力测试

1、模拟数据库数据

vim slap.sh
	...
    
# 执行脚本:
sh slap.sh

2、检查数据可用性

mysql -uroot -p123
select count(*) from oldboy.t1;

3、优化前进行压力测试

mysqlslap --defaults-file=/etc/my.cnf 
 --concurrency=100 --iterations=1 --create-schema='oldboy' 
--query="select * from oldboy.t1 where stuname='alexsb_100'" engine=innodb 
--number-of-queries=2000 -uroot -p123 -verbose

4、创建索引再测试

mysql> alter table t1 add index idx_name(stuname);

# 重复第三步,进行压力测试