Sql中通过sql in or in 的方式拼接sql会导致sql长度过长,Sql执行报错。in 查询效率较慢select * from test where id in('1001','1002') or id in('1001')
in的内容过长后,sql超过数据库对sql长度的设定后会报错in中的内容超过一定的阈值后,超过阈值数据的字段在内存中进行过滤,先查出其它条件符合的数据(sql不做分页查询 ),加载到内存中,最后进行内存分页/**
* 内存分页
*
* @param list 数据
* @param pageNum 当前页
* @param pageSize 分页条数
* @return List
*/
public <T> List<T> pageOperateInMemory(List<T> list, Integer pageNum, Integer pageSize) {
if (CollectionUtils.isEmpty(list)) {
return Collections.emptyList();
}
// 根据当前页和分页条数 从总记录数中取数据
return list.stream().skip((long) pageSize * (pageNum - 1)).limit(pageSize)
.collect(Collectors.toList());
}
In里面的数据,每次查询的时候先写表,再用这张表做关联查询# 方式 1 子查询
select * from master_table x where col_one in(select code from table_temp y where x.col_one=y.code)
select * from test x where exists (select id from test y where y.id=x.id )
# 方式 2 inner join
select x.* from master_table x inner join table_temp y on x.col_one = y.code
id删除数据table_temp| 标识 | 名称 | 含义 |
|---|---|---|
id | id | 一次查询生成的 uuid |
code | 值 | in中的值 |
type | 类型 | 类型 |
request_id | 查询id | 查询id |
15万数据写入空表5秒左右,当表中数据越来越多的时候,写入速度变慢sql拼接更加精确的条件,减少 in的查询范围table_temp 共有 15万mybatis insert方式private void insertOneByOne(List<TempDO> tempDOList) {
StopWatch stopWatch = new StopWatch("task1");
stopWatch.start();
int i = 0;
for (TempDO tempDO : tempDOList) {
testMapper.insertSelective(tempDO);
i++;
if (i == 10000) {
stopWatch.stop();
logger.info(String.valueOf(stopWatch.getTotalTimeMillis()));
i = 0;
}
}
}
// 10000 条 需要 4分29秒
jdbcTemplate方式private void insertOneByOneJdbcExcute(List<TempDO> tempDOList) {
String sql = "INSERT INTO table_temp_one (ID,VER,CODE,ORGCODE,NAME,SHORTNAME,VALIDTIME,INVALIDTIME,PARENTCODE,ORDINAL,CREATEUSER,CREATETIME,PARENTS) VALUES\n" +
"\t (?,?,?,?,?,?,?,?,?,?,?,?,?);\n";
List<Object[]> objectList = new ArrayList<>();
for (TempDO tempDO : tempDOList) {
Object[] object = {
tempDO.getId(), tempDO.getVer(), tempDO.getCode(), tempDO.getOrgcode(), tempDO.getName(), tempDO.getShortname(), tempDO.getValidtime(), tempDO.getInvalidtime(),
tempDO.getParentcode(), tempDO.getOrdinal(), tempDO.getCreateuser(), tempDO.getCreatetime(), tempDO.getParents()
};
objectList.add(object);
}
StopWatch stopWatch = new StopWatch("task1");
stopWatch.start();
int i = 0;
for (Object[] objects : objectList) {
jdbcTemplate.update(sql, objects);
i++;
if (i == 10000) {
stopWatch.stop();
logger.info(String.valueOf(stopWatch.getTotalTimeMillis()));
i = 0;
}
}
}
// 10000 条 需要 4分 36秒
@Insert("")
int insertBatch(TempDO tempDO);
写入 10000 条执行耗时:{}937
写入 10000 条执行耗时:{}734
写入 10000 条执行耗时:{}925
写入 10000 条执行耗时:{}1241
写入 10000 条执行耗时:{}959
写入 10000 条执行耗时:{}999
写入 10000 条执行耗时:{}701
写入 10000 条执行耗时:{}352
写入 10000 条执行耗时:{}582
写入 10000 条执行耗时:{}390
写入 10000 条执行耗时:{}527
写入 10000 条执行耗时:{}388
写入 10000 条执行耗时:{}357
写入 10000 条执行耗时:{}491
写入 10000 条执行耗时:{}300
写入 10000 条执行耗时:{}23
写入 150000 条执行耗时:{}9915
------------------------------------
写入 150000 条执行耗时:{}6206
------------------------------------
写入 150000 条执行耗时:{}5658
写入 150000 条执行耗时:{}6674
写入 150000 条执行耗时:{}7744
SqlSessionFactory sqlSessionFactory = ApplicationContextRegister.getBean(SqlSessionFactory.class);
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
InsertTestMapper mapper = sqlSession.getMapper(InsertTestMapper.class);
List<List<TempDO>> lists = splitList(list, 10000);
StopWatch stopWatch = new StopWatch("totalTask");
stopWatch.start();
for (List<TempDO> tempDOList : lists) {
StopWatch stopWatch1 = new StopWatch("task1");
stopWatch1.start();
mapper.insertBatch(tempDOList);
stopWatch1.stop();
System.out.println("写入 10000 条执行耗时:{}" + stopWatch1.getTotalTimeMillis());
}
sqlSession.commit();
stopWatch.stop();
System.out.println("写入 150000 条执行耗时:{}" + stopWatch.getTotalTimeMillis());
---------------------------------------------------------------
写入 10000 条执行耗时:{}159
写入 10000 条执行耗时:{}106
写入 10000 条执行耗时:{}106
写入 10000 条执行耗时:{}106
写入 10000 条执行耗时:{}106
写入 10000 条执行耗时:{}139
写入 10000 条执行耗时:{}109
写入 10000 条执行耗时:{}106
写入 10000 条执行耗时:{}133
写入 10000 条执行耗时:{}107
写入 10000 条执行耗时:{}107
写入 10000 条执行耗时:{}107
写入 10000 条执行耗时:{}106
写入 10000 条执行耗时:{}107
写入 10000 条执行耗时:{}121
写入 10000 条执行耗时:{}0
写入 150000 条执行耗时:{}4734
---------------------------------------------------------------------
写入 10000 条执行耗时:{}130
写入 10000 条执行耗时:{}105
写入 10000 条执行耗时:{}105
写入 10000 条执行耗时:{}127
写入 10000 条执行耗时:{}135
写入 10000 条执行耗时:{}106
写入 10000 条执行耗时:{}105
写入 10000 条执行耗时:{}133
写入 10000 条执行耗时:{}106
写入 10000 条执行耗时:{}107
写入 10000 条执行耗时:{}111
写入 10000 条执行耗时:{}106
写入 10000 条执行耗时:{}159
写入 10000 条执行耗时:{}142
写入 10000 条执行耗时:{}138
写入 10000 条执行耗时:{}0
写入 150000 条执行耗时:{}6495
PreparedStatement executeBatch 方式Connection connection = SpringContextUtils.getBean(JdbcTemplate.class).getDataSource().getConnection();
String sql = "insert into table_temp(id, request_id,code,type) VALUES (?,?,?,?)";
PreparedStatement ps = null;
try {
ps = connection.prepareStatement(sql);
// 取消自动提交
connection.setAutoCommit(false);
StopWatch stopWatch = new StopWatch("totalTask");
stopWatch.start();
for (int i = 1; i <= list.size(); i++) {
TempDO tempDO = list.get(i - 1);
ps.setObject(1, tempDO.getId());
ps.setObject(2, tempDO.getRequestId());
ps.setObject(3, tempDO.getCode());
ps.setObject(4, tempDO.getType());
ps.addBatch();
if (i % 10000 == 0) {
StopWatch stopWatch1 = new StopWatch("task1");
stopWatch1.start();
ps.executeBatch();
ps.clearBatch();
stopWatch1.stop();
System.out.println("写入 10000 条执行耗时:{}" + stopWatch1.getTotalTimeMillis());
}
}
ps.executeBatch();
ps.clearBatch();
connection.commit();//所有语句都执行完毕后才手动提交sql语句
stopWatch.stop();
System.out.println("写入 150000 条执行耗时:{}" + stopWatch.getTotalTimeMillis());
} catch (SQLException e) {
e.printStackTrace();
} finally {
connection.close();
}
写入 10000 条执行耗时:{}1696
写入 10000 条执行耗时:{}1423
写入 10000 条执行耗时:{}1192
写入 10000 条执行耗时:{}1273
写入 10000 条执行耗时:{}1203
写入 10000 条执行耗时:{}1445
写入 10000 条执行耗时:{}1226
写入 10000 条执行耗时:{}1298
写入 10000 条执行耗时:{}1666
写入 10000 条执行耗时:{}1251
写入 10000 条执行耗时:{}1190
写入 10000 条执行耗时:{}1364
写入 10000 条执行耗时:{}1263
写入 10000 条执行耗时:{}1191
写入 10000 条执行耗时:{}1682
写入 150000 条执行耗时:{}20753
--------------------------------------------------------------------
写入 10000 条执行耗时:{}1579
写入 10000 条执行耗时:{}1859
写入 10000 条执行耗时:{}1483
写入 10000 条执行耗时:{}1470
写入 10000 条执行耗时:{}1488
写入 10000 条执行耗时:{}1059
写入 10000 条执行耗时:{}1112
写入 10000 条执行耗时:{}1164
写入 10000 条执行耗时:{}1426
写入 10000 条执行耗时:{}1202
写入 10000 条执行耗时:{}1315
写入 10000 条执行耗时:{}1654
写入 10000 条执行耗时:{}1301
写入 10000 条执行耗时:{}1134
写入 10000 条执行耗时:{}1529
写入 150000 条执行耗时:{}21168
写入 10000 条执行耗时:{}1267
写入 10000 条执行耗时:{}440
写入 10000 条执行耗时:{}352
写入 10000 条执行耗时:{}524
写入 10000 条执行耗时:{}380
写入 10000 条执行耗时:{}306
写入 10000 条执行耗时:{}457
写入 10000 条执行耗时:{}303
写入 10000 条执行耗时:{}301
写入 10000 条执行耗时:{}804
写入 10000 条执行耗时:{}333
写入 10000 条执行耗时:{}297
写入 10000 条执行耗时:{}323
写入 10000 条执行耗时:{}325
写入 10000 条执行耗时:{}324
写入 150000 条执行耗时:{}6746
---------------------------------------------------------------
写入 10000 条执行耗时:{}372
写入 10000 条执行耗时:{}409
写入 10000 条执行耗时:{}302
写入 10000 条执行耗时:{}303
写入 10000 条执行耗时:{}302
写入 10000 条执行耗时:{}302
写入 10000 条执行耗时:{}370
写入 10000 条执行耗时:{}300
写入 10000 条执行耗时:{}724
写入 10000 条执行耗时:{}302
写入 10000 条执行耗时:{}299
写入 10000 条执行耗时:{}303
写入 10000 条执行耗时:{}299
写入 10000 条执行耗时:{}301
写入 10000 条执行耗时:{}301
写入 150000 条执行耗时:{}5196
写入 10000 条执行耗时:{}379
写入 10000 条执行耗时:{}219
写入 10000 条执行耗时:{}174
写入 10000 条执行耗时:{}165
写入 10000 条执行耗时:{}162
写入 10000 条执行耗时:{}155
写入 10000 条执行耗时:{}227
写入 10000 条执行耗时:{}239
写入 10000 条执行耗时:{}163
写入 10000 条执行耗时:{}202
写入 10000 条执行耗时:{}157
写入 10000 条执行耗时:{}175
写入 10000 条执行耗时:{}166
写入 10000 条执行耗时:{}160
写入 10000 条执行耗时:{}169
写入 150000 条执行耗时:{}4348
50万(table_temp)数据50万2s之内SELECT MASTER_TABLE.ID, MASTER_TABLE.UNITCODE, MASTER_TABLE.CREATETIME, MASTER_TABLE.BILLSTATE, MASTER_TABLE.DEFINECODE, MASTER_TABLE.BILLCODE, MASTER_TABLE.CLASS_NAME, MASTER_TABLE.CLASS_NO, MASTER_TABLE.BILLDATE, MASTER_TABLE.MULTIBASEDATA1, MASTER_TABLE.MULTIBASEDATA2, MASTER_TABLE.MULTIORG1, MASTER_TABLE.MULTIORG2
FROM MASTER_TABLE
WHERE
(MASTER_TABLE.UNITCODE in (select code from table_temp))

3-4 sSELECT MASTER_TABLE.ID, MASTER_TABLE.UNITCODE, MASTER_TABLE.CREATETIME, MASTER_TABLE.BILLSTATE, MASTER_TABLE.DEFINECODE, MASTER_TABLE.BILLCODE, MASTER_TABLE.CLASS_NAME, MASTER_TABLE.CLASS_NO, MASTER_TABLE.BILLDATE, MASTER_TABLE.MULTIBASEDATA1, MASTER_TABLE.MULTIBASEDATA2, MASTER_TABLE.MULTIORG1, MASTER_TABLE.MULTIORG2
FROM MASTER_TABLE
WHERE exists (
select code from table_temp y where MASTER_TABLE.UNITCODE = y.code
)

2s之内SELECT MASTER_TABLE.ID, MASTER_TABLE.UNITCODE, MASTER_TABLE.CREATETIME, MASTER_TABLE.BILLSTATE, MASTER_TABLE.DEFINECODE, MASTER_TABLE.BILLCODE, MASTER_TABLE.CLASS_NAME, MASTER_TABLE.CLASS_NO, MASTER_TABLE.BILLDATE, MASTER_TABLE.MULTIBASEDATA1, MASTER_TABLE.MULTIBASEDATA2, MASTER_TABLE.MULTIORG1, MASTER_TABLE.MULTIORG2
FROM MASTER_TABLE
inner join table_temp x on MASTER_TABLE.UNITCODE = x.code

临时表只在当前连接可见,当关闭连接时,Mysql会自动删除表并释放所有空间。
外部临时表:通过CREATE TEMPORARY TABLE 创建的临时表,这种临时表称为外部临时表。这种临时表只对当前用户可见,当前会话结束的时候,该临时表会自动关闭。这种临时表的命名与非临时表可以同名(同名后非临时表将对当前会话不可见,直到临时表被删除)。
内部临时表:内部临时表是一种特殊轻量级的临时表,用来进行性能优化。这种临时表会被MySQL自动创建并用来存储某些操作的中间结果。内部临时表在SQL语句的优化过程中扮演着非常重要的角色, MySQL中的很多操作都要依赖于内部临时表来进行优化。但是使用内部临时表需要创建表以及中间数据的存取代价,所以用户在写SQL语句的时候应该尽量的去避免使用临时表。
如果超出了临时表的容量,临时表会转换成磁盘表
MySQL用于存储一些中间结果集的表,临时表只在当前连接可见,当关闭连接时,Mysql会自动删除表并释放所有空间。# 创建 临时表语句
create temporary table tb_temporay(id varchar(36),name varchar(30),code varchar(30));
sql元数据信息并没有这张表
GROUP BY。select count(*) from tb_data group by string1;

EXPLAIN 查看执行计划结果的 Extra 列中,如果包含 Using Temporary 就表示会用到临时表。
SQL语句关联的表在2张及以上,并且和一些小表关联。可以采用将大表进行分拆并且得到比较小的结果集合存放在临时表中。MyISAM,但是可以修改。内存表的表结构建立在磁盘里面,数据放在内存里面;
当MySQL断开当前连接后,临时表的表结构和表数据都没了,但内存表的表结构和表数据都存在;当MySQL服务重启之后,内存表的数据会丢失,但表结构依旧存。
CREATE TABLE语句,但需要将存储引擎设置为:ENGINE = MEMORYcreate table tb_one (id varchar(36),name varchar(30),code varchar(30))ENGINE = MEMORY;
insert into tb_one(id,name,code) values('1','2','3')
| 临时表 | 内存表 | |
|---|---|---|
| 存储 | 表结构和数据都存储在内存中 | 表结构存储在磁盘中,表数据存储在内存中 |
| 会话 | 单个会话独享的,是会话级别的 | 可以多个会话共享 |
| 引擎 | 临时表默认,myisam | 内存表默认,memory |
| 断开连接 | 表结构和表数据都没了 | 表结构和表数据都存在 |
| 服务重启 | 表结构和表数据都没了 | 表结构存在,表数据不存在 |
| 性能 | 由于表数据都是存放在内存中,所以相对来说,查询速度较快,但是数据的维护较为困难 |
view)是在基本表之上建立的表,它的结构(即所定义的列)和内容(即所有数据行)都来自基本表,它依据基本表存在而存在。