232:详细描述一下不走索引的一些情况以及“坑”,进行一次演讲。
(由于该题篇幅太长,文章字数限制,在这里只展示了小标题,随后会贴出此题详细内容专题)
1. 没有查询条件,或者查询条件没有建立索引
2. 在查询条件上没有使用引导列
3. 查询的数据量是大表的大部分,应该是30%以上(主键索引除外) -----可以走全表扫描
4. 索引本身失效
5. 查询条件使用函数在索引列,或者对索引列进行运算,运算包括(+ - * / !等)
6. 对小表查询
7. 提示不使用索引(也就是在select的时候忽略索引)
8. 统计数据不真实
9. CBO计算走索引花费过大的情况
10. 隐式转换导致索引失效,这一点应当引起重视,也是开发中经常会犯的错
11.不等于<>不一定不走索引
12. like 和<>"%_" 百分号在前;not like ,不管是%放在后面还是前面
13. 表没分析
14. not in,not exist
15. 当变量采用的是times变量,而表的字段采用的是data变量时,或相反情况
16. B-tree索引 is null,is not null处理的不是很好
233:识别 ddl 操作,确认哪些操作属于 ddl。
DDL(datedefinition languages)语句:数据定义了语言,定义了数据库、表、索引等对象的定义。常用的语句包括create、drop、alter等
1.创建数据库
mysql> createdatabase test2 ;
Query OK, 1 rowaffected (0.00 sec)
row affected表示有一行记录受到影响
sec表示这个操作的执行时间
2.查看数据库
mysql> showdatabases;
+--------------------+
| Database |
+--------------------+
|information_schema |
| mysql |
|performance_schema |
| sakila |
| test |
| test1 |
| test2 |
+--------------------+
7 rows in set(0.01 sec)
information_schema:存储了系统中一些对象信息,如:用户表信息,试图信息,各种数据库变量状态、字符集信息等
mysql:主要是用户的相关权限信息
performance_schema:记录系统性能的数据库。通过performance_schema变更决定是否开启,默认不是开启的
test:测试数据库
注意:数据库和表名是否区别大小写由一个参数决定:
lower_case_table_mames
当值为1时,表名和库名对大小写不敏感,用小写保存在硬盘上;设置为0时,按指定的名字保存在硬盘上,大小写敏感
3.选择数据库
mysql> usesakila;
Database changed
4.查看表
mysql> showtables;
+----------------------------+
|Tables_in_sakila |
+----------------------------+
| actor |
|actor_info |
| address |
| category |
| city |
| country |
| customer |
|customer_list |
| film |
|film_actor |
|film_category |
| film_list |
| film_text |
| inventory |
| language |
|nicer_but_slower_film_list |
| payment |
| rental |
|sales_by_film_category |
|sales_by_store |
| staff |
|staff_list |
| store |
+----------------------------+
23 rows in set(0.00 sec)
5.删除数据库
mysql> dropdatabase test2 ;
Query OK, 0 rowsaffected (0.04 sec)
删除数据库后,数据库下面所有的表都会被删除。
6.创建表
语法:
create tabletablename(
column_name1 column_type1 constrains,
column_name2 column_ytpe2 constraints,
......
column_nameN colume_tupeN constraints);
column_name 字段名称
column_type 字段类型
constraints 字段的约束
注意:表名额可以包括字母、数字,下划线和美元符号,但不能完全是数字。
取表名和数据库名的原则是看其名和其意
mysql> createtable emp(
-> name varchar(10) ,
-> hirdate date,
-> sal decimal(10,2),
-> depton int);
Query OK, 0 rowsaffected (0.02 sec)
7.查看表结构
desc tablename
mysql> descemp ;
+---------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------+------+-----+---------+-------+
| name | varchar(10) | YES | | NULL | |
| hirdate |date | YES | |NULL | |
| sal | decimal(10,2) | YES | |NULL | |
| depton | int(11) | YES | | NULL | |
+---------+---------------+------+-----+---------+-------+
4 rows in set(0.01 sec)
Filed:字段名称
Type:字段类型
Null:是否可以为空
Key:是否有索引
Default:是否有默认值
8.查看具体表
show createtable tablename
mysql> showcreate table emp \G
***************************1. row ***************************
Table: emp
Create Table:CREATE TABLE `emp` (
`name` varchar(10) DEFAULT NULL,
`hirdate` date DEFAULT NULL,
`sal` decimal(10,2) DEFAULT NULL,
`depton` int(11) DEFAULT NULL
) ENGINE=InnoDBDEFAULT CHARSET=utf8
1 row in set(0.00 sec)
除了看到表的定义外,可以看到表使用的存储引擎engine=innodb,使用的字符集charset=utf8。"\G"的意思是使得记录能够按照竖排显示,更易阅读
9.约束
[NOT NULL |NULL] 是否可以为空
[DEFAULEdefault_value] 是否有默认值
[AUTP_INCREMENT] 是否是自动增长
[UNIQUE [KEY] |[RPIMARY] KEY] 是否是主键
[CONMENT'string'] 注释
mysql> CREATETABLE city(
->city_id intNOT NULL AUTO_inCREMENt,
->cityvarchar(50) NOT NULL comment 'city name',
->country_namevarchar(20) NOT NULL default 'china',
->KEY(city_id)
->);
Query OK, 0 rowsaffected (0.01 sec)
10.插入数据
mysql> insertinto city(city) values('beijing');
Query OK, 1 rowaffected (0.01 sec)
11.创建相似表
create tabletable_name like table_name1;
mysql> createtable city_bak like city;
Query OK, 0 rowsaffected (0.02 sec)
12.增加表字段
语法
alter tabletablename ADD col_name column_definition [FIRST | AFTER col_name]
mysql> altertable emp add column age int(3);
Query OK, 0 rowsaffected (0.09 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> descemp;
+---------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------+------+-----+---------+-------+
| name | varchar(10) | YES | | NULL | |
| hirdate |date | YES | |NULL | |
| sal | decimal(10,2) | YES | |NULL | |
| depton | int(11) | YES | | NULL | |
| age | int(3) | YES | | NULL | |
+---------+---------------+------+-----+---------+-------+
5 rows in set(0.00 sec)
13.修改字段类型
语法:
alter tabletablename MODIFY col_name column_definition [FIRST | AFTER col_name]
mysql> altertable emp modify name varchar(20);
Query OK, 0 rowsaffected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> descemp;
+---------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------+------+-----+---------+-------+
| name | varchar(20) | YES | | NULL | |
| hirdate |date | YES | |NULL | |
| sal | decimal(10,2) | YES | |NULL | |
| depton | int(11) | YES | | NULL | |
| age | int(3) | YES | | NULL | |
+---------+---------------+------+-----+---------+-------+
5 rows in set(0.00 sec)
14.修改字段排列顺序
mysql> altertable emp modify hirdate date first;
Query OK, 0 rowsaffected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> descemp;
+---------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------+------+-----+---------+-------+
| hirdate |date | YES | |NULL | |
| name | varchar(20) | YES | | NULL | |
| sal | decimal(10,2) | YES | |NULL | |
| depton | int(11) | YES | | NULL | |
| age | int(3) | YES | | NULL | |
+---------+---------------+------+-----+---------+-------+
5 rows in set(0.00 sec)
15.删除表字段
语法:
alter tabletablename DROP col_name
mysql> altertable emp drop age;
Query OK, 0 rowsaffected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> descemp;
+---------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------+------+-----+---------+-------+
| hirdate |date | YES | |NULL | |
| name | varchar(20) | YES | | NULL | |
| sal | decimal(10,2) | YES | |NULL | |
| depton | int(11) | YES | | NULL | |
+---------+---------------+------+-----+---------+-------+
4 rows in set(0.00 sec)
16.字段改名
alter tabletablename CHANGE old_col_name new_col_name column_definition [FIRST |AFTERcol_name]
mysql> altertable emp change deption depton1 int(11);
Query OK, 0 rowsaffected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> descemp;
+---------+---------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------+------+-----+---------+-------+
| hirdate |date | YES | |NULL | |
| name | varchar(20) | YES | | NULL | |
| sal | decimal(10,2) | YES | |NULL | |
| depton1 |int(11) | YES | |NULL | |
+---------+---------------+------+-----+---------+-------+
4 rows in set(0.00 sec)
注意:change和modify都可以修改表的定义,不同的是change后面需要写两次列名。但是change的优点是可以修改列名称,modify则不能。
change/first/after这些关键字是MySQL在标准SQL上的扩展,在其他数据库上不适用。
17.更改表名
语法:
alter tabletablename RENAME [TO] new_tbl_name;
mysql> altertable emp rename emp1;
Query OK, 0 rowsaffected (0.00 sec)
18.删除表
语法:
drop tabletablename;
mysql> droptable emp;
Query OK, 0 rowsaffected (0.00 sec)
19.创建索引
语法:
CREATE[UNIQUE|FULLTEXT|SPATIAL] INDEX index_name
[USING index_type]
ON tbl_name (index_col_name,...)
index_col_name:
col_name [(length)] [ASC | DESC]
mysql> createindex ind_emp_dept using btree on emp(depton);
Query OK, 0 rowsaffected (0.10 sec)
Records: 0 Duplicates: 0 Warnings: 0
注意:索引起名最好以ind开头或者idx等类似index开头,做到看其名字知其意,创建索引默认是BTREE索引
使用altertable也可以创建和删除索引
20.删除索引
语法:
drop indexindex_name on table_name;
mysql> dropindex ind_emp_dept on emp;
Query OK, 0 rowsaffected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0
21.创建视图
视图是一种虚拟存在的表,对于使用视图的用户来说是透明的。视图在数据库中并不占用存储空间。在使用过程中的数据是从实际存在的表动态生成的。
简单:使用视图的用户完全不用关心后面对应的表机构和筛选条件,对用户来说是已经过滤好的复合条件的结果集
安全:使用视图的用户只能访问他们被允许查询的结果集。
语法:
CREATE [ORREPLACE]
VIEW view_name[(column_list)]
ASselect_statement
[WITH [CASCADED| LOCAL] CHECK OPTION];
其中,[WITH[CASCADED | LOCAL] CHECK OPTION],决定了是否允许更新数据使用记录不再满足视图的条件。
*LOCAL是只要满足本视图的条件就可以更新
*CASCADED 是必须满足所有针对创建该视图的相关视图的条件才可以更新,这是默认选项
234:ddl 的风险,如何对 ddl 的风险进行测试。
MySQL数据库在执行DDL操作时会锁表,在数据量大的情况下会消耗特别多的资源,在实际生产中会造成阻塞。可以通过压力测试进行生产上的模拟,然后连接一个客户端执行DDL操作,并观察数据库的性能状态。
235:识别 ddl 对应的算法和锁,对于锁的深度认识,特别是对于 lock=none 的真相。
当对一个表做DDL的时候:
1.查看表上是否有TM:RX锁,如果有,则等待对应的事务完成。(如果之前的RX锁一直不释放,阻塞后面大量新来的RX,而不是转换者队列的,可能导致数据库hang住挂起)
2.之后过来想做DML的进程都在后面排队
3.事务完成后,释放行锁,释放TM:RX,随后就可以加上TM:X锁
4.对表进行DDL操作
当在表上建索引的时候:会给表加上S锁,任何人不能修改。
236:online ddl 对应的坑。
海量的 io、短暂的加上 exclusive 或者 shared 锁。
Online DDL有 LOCK 选项控制是否锁表,根据不同的DDL操作类型有不同的表现:默认mysql尽可能不去锁表,但是像修改主键这样的昂贵操作不得不选择锁表。
1.LOCK=NONE,即DDL期间允许并发读写涉及的表,比如为了保证 ALTER TABLE 时不影响用户注册或支付,可以明确指定,好处是如果不幸该alter语句不支持对该表的继续写入,则会提示失败,而不会直接发到库上执行。ALGORITHM=COPY默认LOCK级别;
2.LOCK=SHARED,即DDL期间表上的写操作会被阻塞,但不影响读取。
3.LOCK=DEFAULT,让mysql自己去判断lock的模式,原则是mysql尽可能不去锁表
4.LOCK=EXCLUSIVE,即DDL期间该表不可用,堵塞任何读写请求。如果你想alter操作在最短的时间内完成,或者表短时间内不可用能接受,可以手动指定。
但是有一点需要说明,无论任何模式下,online ddl开始之前都需要一个短时间排它锁(exclusive)来准备环境,所以alter命令发出后,会首先等待该表上的其它操作完成,在alter命令之后的请求会出现等待waiting meta data lock。同样在ddl结束之前,也要等待alter期间所有的事务完成,也会堵塞一小段时间。所以尽量在ALTER TABLE之前确保没有大事务在执行,否则一样出现连环锁表。
237:开发经常会对表进行 ddl,如何规范 ddl 操作,写出一个规范的流程
提交给 ddl 需求给 dba
限制开发人员对数据库的 ddl 权限
dba 进行测试:io 测试、时间测试、是否支持 in place、none,显式的加上lock none
dba 形成操作规范和风向评估报告,走流程审批进行相关的操作
238:分区表的四大好处。
1. 易维护,数据量小,可以对单独的分区进行相关操作,备份和恢复方便。
2. 减少IO,分区表的数据文件独立成为ibd,可以放在不同的物理磁盘上,减轻磁盘负载。
3. 减少单表索引和锁的互斥。
4. 性能提升,提高查询效率,数据独立和索引独立。
239:建立一个以年和以天分区的表,要求带上maxvalue
CREATE TABLE employees (
idINT NOT NULL,
fnameVARCHAR(30),
lnameVARCHAR(30),
hiredDATE NOT NULL DEFAULT '1970-01-01',
separatedDATE NOT NULL DEFAULT '9999-12-31',
job_codeINT,
store_idINT
)
分区列 separated.
ENGINE=INNODB
PARTITON BYRANGE (YEAR(SEPARATED)) (
PARTTION p2014VALUE LESS THEN (2015),
PARTTION p2015VALUE LESS THEN (2016),
PARTTION p2016VALUE LESS THEN (2017),
PARTTION p2017VALUE LESS THEN MAXVALUE
);
240:建立一个人口表,要求按照出生的省份做一个列表分区,每一个省一个分区。
create tablepeople(
id int not null,
name varchar(20)not null,
born data,
provincevarchar(10) not null,
) ENGINE=INNODB
PARTITON BYLIST(PROVINCE) (
PARTTION p0VALUE IN (‘SHANDONG’),
PARTTION p1VALUE IN (‘BEIJING’)
……
);
241:5.6 支持 hash 分区,对于 240建立的人口表,进一步细分出来 hash 分区,每一个省份的分区在出生年月这个列上建立 16 个子分区。
ENGINE=INNODB
PARTITION BYHASH(data)
PARTITION 16;