@javazjm
2017-12-27T18:01:31.000000Z
字数 4981
阅读 1610
面试知识
项目部署之前,在启动MySQL数据库时开启慢查询,并把执行慢的语句写到日志中,在运行一段时间后,通过查看日志找到慢查询语句。
使用explain来详细分析语句的执行过程。
数据库表设计时需要遵循的方式
表的范式,首先符合1NF,才能满足2NF,进一步满足3NF。
研发中,经常使用的存储引擎 myisam/ innodb/ memory
特点 | Myisam | InnoDB | BDB | Memory | Archive |
---|---|---|---|---|---|
存储限制 | 没有 | 64TB | 没有 | 有 | 没有 |
批量插入速度 | 高 | 低 | 高 | 高 | 非常高 |
事务安全 | 支持 | 支持 | |||
锁机制 | 表锁 | 行锁 | 页锁 | 表锁 | 行锁 |
B树索引 | 支持 | 支持 | 支持 | 支持 | |
哈希索引 | 支持 | 支持 | |||
全文索引 | 支持 | ||||
集群索引 | 支持 | ||||
数据缓存 | 支持 | 支持 | |||
索引缓存 | 支持 | 支持 | 支持 | ||
数据可压缩 | 支持 | 支持 | |||
空间使用 | 低 | 高 | 低 | N/A | 非常低 |
内存使用 | 低 | 高 | 低 | 中等 | 低 |
支持外键 | 支持 |
索引(Index)是帮助 DBMS 高效获取数据的数据结构。
分类:普通索引|唯一索引|主键索引|全文索引
alter table dept ad index my_index(dname,loc); -- dname左边的列,loc右边的列
explain select * from dept where dname='aaa'\G -- 会使用到索引
explain select * from dept where loc='aaa'\G -- 不会使用到索引
explain select * from dept where dname like '%aaa'\G -- 不会使用到索引
explain select * from dept where dname like 'aaa%'\G -- 会使用到索引
所以在 like 查询时,’关键字‘ 最前面不能使用 % 或者 _ 这样的字符,如果一定要前面有变化的值,则考虑使用 全文索引 -> sphinx。
3. 如果条件中有or,有条件没有使用索引,即使其中有条件带索引也不会使用,换言之,就是要求使用的所有字段,都必须单独使用时能使用索引。可以考虑用in 或 union 替换or。
4. 如果列类型是字符串,一定要在条件中将数据使用引号引用起来,否则不使用索引
explain select * from dept where dname='1111';
explain select * from dept where dname=1111; -- 数值自动转字符串
explain select * from dept where dname=qqq; -- 报错
也就是说,如果列是字符串类型,无论是不是字符串,数字一定要用 ’‘ 把它括起来。
5. 如果 MySQL 估计使用全表扫描比使用索引快,则不使用索引。
表里面只有一条记录。
分表分为水平(按行)分表 和 垂直(按列)分表。
根据经验,MySQL 表数据一般达到百万级别,查询效率会很低,容易造成表锁,甚至堆积很多连接,直接挂掉,水平分表能够很大程度减少这些压力。(按行数据进行分类)
如果一张表中某个字段值非常多(成文本,二进制等),而且只有在很少的情况下回查询,这时候就可以把字段单独放到一个表,通过外键关联起来。
考试详情,一般我们只关注分数,不关注详情。
一台数据库支持的最大并发数是有限的,如果用户并发访问太多,一台服务器满足不了要求,就可以集群处理,MySQL的集群处理技术最常用的就是读写分离。
数据库最终会把数据持久化到磁盘,如果集群就必须保证每个数据库服务器的数据是一致的,能改变数据库数据的操作都往主数据库写,而其他数据库从主数据库上同步数据。
使用负载均衡来实现写的操作都往主数据库去,而读的数据往从数据库。
在持久层和数据库之前添加一个缓存层,如果用户访问的数据已经缓存起来时,在用户访问时直接从缓存中获取,不用访问数据库。而缓存是在内存级的,访问速度快。
作用
减少数据库服务器压力,减少访问时间,提高系统响应速度。
Java中常用的缓存有,hibernate 的二级缓存,但是该缓存不能完成分布式缓存。
可使用redis 作为中央缓存。
-- 去除键
alter table test DISABLE keys;
-- 批量插入数据
insert into test select * from test1;
-- 恢复键
alter table test ENABLE keys;
set unique_checks=0 -- 关闭
set unique_checks=1 -- 开启
set autocommit=0 -- 关闭
-- 批量插入
set autocommit=1 -- 开启
变多次提交为一次
insert into test values(1,2);
insert into test values(1,3);
insert into test values(1,4);
-- 合并多条为一条
insert into test values(1,2),(1,3),(1,4);
--
explain
select * from customer where customer_id not in (select DISTINCT customer_id from payment) ;
-- 基于索引外链
explain
select * from customer c left join payment p on (c.customer_id=p.customer_id) where p.customer_id is null;
or 优化
在两个独立索引上使用or 的性能优化
limit 优化
select a.film_id,a.description from film a order by a.title limit 50,5;
-- 优化
select a.film_id,a.description from film a inner join (selet film_id from film order by title limit 50,5) b on a.film_id=b.film_id
变多次提交为一次
String JDBC_URL = "jdbc:mysql://localhost:3306/samp_db";
String JDBC_USERNAME = "root";
String JDBC_PASSWORD = "root";
Connection connection = DriverManager.getConnection(JDBC_URL + "?useServerPrepStmts=false&rewriteBatchedStatements=true",JDBC_USERNAME,JDBC_PASSWORD);
connection.setAutoCommit(false);
PreparedStatement cmd = connection.prepareStatement("insert into test1 values(?,?)");
for (int i = 0; i < 1000000; i++) {//100万条数据
cmd.setInt(1, i);
cmd.setString(2, "test");
cmd.addBatch();
if(i%1000==0){
cmd.executeBatch();
}
}
cmd.executeBatch();
connection.commit();
cmd.close();
connection.close();
省出的时间相当可观,像这种操作能不使用代码就不要使用代码,可以使用存储过程代替。