当不能直接进行sql
联表查询的时候,一些中间数据需要写到表中进行查询从而解决一些无法解决的问题
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 |
id
hash
到随机表进行写表15
万数据写入空表5
秒左右,当表中数据越来越多的时候,写入速度变慢sql
不是很理想、并且在写完表后还有后续查询逻辑,sql
查询不是特别理想join
方式比 in
子查询的方式快in
子查询在遇到分页的问题的时候会比较慢,推荐优先使用 join
方式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 *
FROM MASTER_TABLE
WHERE
(MASTER_TABLE.CODE in (select code from table_temp))
3-4 s
SELECT *
FROM MASTER_TABLE
WHERE exists (
select code from table_temp y where MASTER_TABLE.CODE = y.code
)
2s
之内SELECT *
FROM MASTER_TABLE
inner join table_temp x on MASTER_TABLE.CODE = x.code
15
万数据
10000
条一次比5000、1000
条一次写入速度快
固化表
增加code
索引后写入变慢
手动提交事务比自动提交事务快
固化表追加方式写的时候越往后越慢
150000
条执行耗时:9995
150000
条执行耗时:9924
固化表
只有主键比较项 | 插入数据量 | 固化表 | 固化表(追加数据) | 临时表 | 临时表(追加数据) |
---|---|---|---|---|---|
单条插入 | 10000 条 |
4 分29 秒 |
|||
多values 方式插入自动提交事务 |
15 万 |
3 次平均6.624 秒 |
3 次平均 7.313 秒 |
3 次(每次重新创建临时表)平均4.9 秒 |
越往后越慢 |
多values 方式插入手动提交事务 |
15 万 |
3 次/6.15 秒 |
3 次平均6.01 秒 |
3 次(每次重新创建临时表)平均4 秒 |
3 次(第一次创建临时表,后面两次追加)平均5.8 秒 |
固化表 code
设置索引比较项 | 插入数据量 | 固化表 | 固化表(追加数据) |
---|---|---|---|
多values 方式插入自动提交事务 |
15 万 |
3 次平均7.25 秒 |
3 次平均 9.04 秒 |
多values 方式插入手动提交事务 |
15 万 |
3 次/7.24 秒 |
3 次平均9.43 秒 |
固化表
只有主键插入数据量 | 比较项 | 固化表 | 固化表(追加数据) |
---|---|---|---|
15 万 |
多values 方式插入自动提交事务 |
3 次平均5.938 秒:5606、6587、5621 |
3 次平均 8.386 秒:7510、8408、9240 |
15 万 |
多values 方式插入手动提交事务 |
3 次/6.050 秒:5728、6762、5661 |
3 次平均6.582 秒:5661、6462、7625 |
固化表 code
设置索引比较项 | 插入数据量 | 固化表 | 固化表(追加数据) |
---|---|---|---|
多values 方式插入自动提交事务 |
15 万 |
3 次平均7.839 秒:7840、7662、8015 |
3 次平均 9.15 秒:7373、9185、10921 |
多values 方式插入手动提交事务 |
15 万 |
3 次/6.916 秒:6427、7139、7166 |
3 次平均9.276 秒:6781、9278、11769 |
固化表 code
增加索引后三种方式秒出
固化表
不加 code
索引、join
方式查询最快
固化表
只有主键
比较项 | 主表数据50 万(固化表) 数据45 万 |
---|---|
in 作为子查询 |
2.584s、2.547s、2.546s |
exist 查询 |
5.72s、5.91s、5.94s |
inner join 查询 |
1.638s、1.661s、1.640s |
固化表 code
设置索引比较项 | 主表数据50 万(固化表) 数据45 万 |
---|---|
in 作为子查询 |
秒出 |
exist 查询 |
秒出 |
inner join 查询 |
秒出 |
sql
插入多 values
方式速度比较快sql
查询使用 left join
比使用 in
子查询的方式快很多临时表只在当前连接可见,当关闭连接时,Mysql
会自动删除表并释放所有空间。
外部临时表:通过CREATE TEMPORARY TABLE
创建的临时表,这种临时表称为外部临时表。这种临时表只对当前用户可见,当前会话结束的时候,该临时表会自动关闭。这种临时表的命名与非临时表可以同名(同名后非临时表将对当前会话不可见,直到临时表被删除)。
内部临时表:内部临时表是一种特殊轻量级的临时表,用来进行性能优化。这种临时表会被MySQL
自动创建并用来存储某些操作的中间结果。内部临时表在SQL
语句的优化过程中扮演着非常重要的角色, MySQL
中的很多操作都要依赖于内部临时表来进行优化。但是使用内部临时表需要创建表以及中间数据的存取代价,所以用户在写SQL
语句的时候应该尽量的去避免使用临时表。
如果超出了临时表的容量,临时表会转换成磁盘表
MySQL
用于存储一些中间结果集的表,临时表只在当前连接可见,当关闭连接时,Mysql
会自动删除表并释放所有空间。# 创建 临时表语句
create temporary table tb_temporay(id varchar(36),name varchar(30),code varchar(30));
GROUP BY。
select count(*) from tb_data group by string1;
SQL
语句关联的表在2
张及以上,并且和一些小表关联。可以采用将大表进行分拆并且得到比较小的结果集合存放在临时表中。MyISAM
,但是可以修改。内存表的表结构建立在磁盘里面,数据放在内存里面;
当MySQL
断开当前连接后,临时表的表结构和表数据都没了,但内存表的表结构和表数据都存在;当MySQL
服务重启之后,内存表的数据会丢失,但表结构依旧存。
CREATE TABLE
语句,但需要将存储引擎设置为:ENGINE = MEMORY
create 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
)是在基本表之上建立的表,它的结构(即所定义的列)和内容(即所有数据行)都来自基本表,它依据基本表存在而存在。使用临时表详情:https://blog.csdn.net/qq_37248504/article/details/127349776