一 循环问题
1 避免循环中创建连接数据库、读写数据库、读写文件、调用接口、new 新对象等。否则会影响接口响应速度,导致服务器资源高位占用。
不推荐的写法:
public void run(){
for (int i=0;i<integers.length;i++) {
String content = “测试”+i;
RandomAccessFile rFile = new RandomAccessFile(fName, "rw");
long fileLength = rFile.length();
rFile.seek(fileLength);
rFile.writeBytes(content);
rFile.close();
}
}
推荐的写法:
public void run(){
String content = “”;
for (int i=0;i<integers.length;i++) {
content = content + “测试” + i;
}
RandomAccessFile rFile = new RandomAccessFile(fName, "rw");
long fileLength = rFile.length();
rFile.seek(fileLength);
rFile.writeBytes(content);
rFile.close();
}
2 不要在循环中使用try…catch…,推荐把其放在最外层。
不推荐的写法:
public void run(){
int [] integers={1,2,3,4};
for (int i=0;i<integers.length;i++) {
try {
//业务处理逻辑
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
推荐的写法:
public void run(){
int [] integers={1,2,3,4};
try {
for (int i=0;i<integers.length;i++) {
//业务处理逻辑
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
二 资源释放
1 文件句柄、scoket连接、数据库连接、redis连接等资源类,在任何情况下确保释放资源。
不推荐的写法:
try {
XXX.close(); //抛异常,导致YYY.close不能释放资源
YYY.close();
} catch (Exception e) {
}
推荐的写法:
try {
XXX.close(); //抛异常
} catch (Exception e) {
}
try {
YYY.close(); //抛异常
} catch (Exception e) {
}
2 Socket设置即时释放。
推荐的写法:
public void run(String[] args) {
try {
Socket socket = new Socket();
//设置立即释放连接
socket.setSoLinger(true, 0);
//设置读取超时时间,单位毫秒
socket.setSoTimeout(2000);
SocketAddress address = new InetSocketAddress(host, port);
socket.connect(address);
OutputStream output = socket.getOutputStream();
StringBuilder strB = new StringBuilder();
strB.append("a");
byte[] request = strB.toString().getBytes("utf-8");
output.write(request);
} catch (IOException e) {
throw e;
} finally {
socket.close();
}
}
三 文件读写
1 文件读写增加锁机制,解决高并发读写问题。
推荐的写法:
public void run(String[] args) {
RandomAccessFile randomAccessFile = null;
FileChannel channel = null;
try {
randomAccessFile = new RandomAccessFile("test.txt", "rw");
channel = randomAccessFile.getChannel();
FileLock lock = null;
int sum=0;
while (null == lock) {
if(sum > 10) {
return false; //超过重试次数后退出
}
try {
lock = channel.lock();
} catch (Exception e) {
sum++;
sleep(500);
}
}
randomAccessFile.writeByte(‘A’);
lock.release();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != randomAccessFile) {
randomAccessFile.close();
}
if (null != channel) {
channel.close();
}
}
}
四 SQL优化
-
确保where 子句查询条件必须走索引,尽量使用主键或唯一索引列,大批数据应考虑分页方式处理数据。
确认where 及 order by 涉及的列上建立索引。 -
避免where 子句中对字段进行null、!= 、<>、not in、not exists值或
区间范围过大,将导致引擎放弃使用索引而进行全表扫描。
可以在num上设置默认值0,确保表中num列没有null值:
select id from t where num is null;
推荐改为:
select id from t where num = 0;
-
表的索引数最好不要超过6个,索引可提高相应的 select 的效率,但同时
降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重
建索引,所以怎样建索引需要慎重考虑。 -
避免在索引列上使用计算
在where字句中,如果索引列是计算或者函数的一部分,DBMS的优化器将不
会使用索引而使用全表查询,函数属于计算的一种。
低效:
select id from t where id+1=8;
优化:
select id from t where id=9;
-
SQL不用 * 查询,需要明确查询所需字段。
-
使用表的别名,当在SQL语句中连接多个表时,请使用表的别名并把别名前缀于每个列名上。这样就可以减少解析的时间并减少哪些有列名歧义引起的语法错误。
-
SQL语句的合并和拆分。尽量将多条SQL语句压缩到一句SQL中
合并案例:
update t set status=’01’,updatetime=now() where id=1;
update t set status=’01’,updatetime=now() where id=2;
合并成:
update t set status=’01’,updatetime=now() where id in(1,2);
拆分案例:
select id, num from t where num=10 or num=20
拆分成:
select id, num from t where num=10
union all
select id, num from t where num=20
- 尽量使用union all替换union,因为union需要增加去重处理。
- ORACLE使用 MERGE INTO 代替 UPDATE 执行批量更新,会提升执行效率。
merge into s_manager a
using(SELECT 1 managerid from DUAL) b on (a.managerid = b.managerid)
when matched then update set a.CNAME='abc'
when not matched then insert(managerid,CNAME) values(1,'abcdef');
MYSQL Innodb引擎的on duplicate key update实现merge into语法。
insert into user(id,name) values(1, 'abc') on duplicate key update
name= 'abcdef';
-
尽量避免使用游标。
-
用varchar/nvarchar 代替 char/nchar,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。比如:char(100) 型,在字段建立时,空间就固定了,不管是否插入值(NULL也包含在内),都是占用 100个字符的空间,如果是varchar这样的变长字段,null 不占用空间。
-
用where子句替换having字句,having只会在检索出所有记录之后才对结果集进行过滤,而where则是在聚合前。
-
尽量不要使用联表查询,特别是大数据表操作时;使用多条SQL批量查询后,组装结果。
-
经常使用的小表考虑改成配置文件方式,减少数据库查询。经常使用的多列大表考虑拆分2个表,常用字段内容放小热表中,减少数据库块读取的压力。
-
SQL多个排序条件,确保排序唯一,否则分页时会有异常。
-
数据库尽量不要用大内容字段,否则在查询和编辑时影响性能。
-
使用SQL预处理语句绑定参数方式,防止sql注入,提高SQL执行效率。
-
数据事务处理时,SQL执行语句按照表名顺序执行,控制SQL影响行数,提高每条SQL执行速度,尽可能减少死锁情况发生。
-
数据库表增加字段,如果设置为内容必填时,需要考虑跨系统异常,因为其他系统有可能新增记录时,这个新字段未做处理。
-
根据业务合理使用分库分表,对合理清理历史数据,提高查询速度。
-
尽量使用逻辑删除,删除\修改操作必须确保查询条件范围可控,否则可能删除\修改期望之外的数据,甚至全表。
update t_user set status=’09’ where 1=1; 代码缺陷导致没指定条件。 -
注意int最大值2147483647,合理使用bigint字段类型。
-
mysql参数binlog_row_image默认值full这个对alibaba/canal有影响:
full:在“before”和“after”影像中,记录所有的列值;
minimal:在“before”和“after”影像中,仅仅记录被更改的以及能够唯一识别数据行的列值;
noblob:在“before”和“after”影像中,记录所有的列值,但是BLOB 与 TEXT列除外(如未更改)。
查询:select @@global.binlog_row_image;
设置:set @@global.binlog_row_image=‘full’; -
使用短索引,如果有一个CHAR(255)的列,如果在前10 个或20 个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。