java多样查询_mysql如何查询多样同样的表/sql分表查询、java项目日志表分表的开发思路/按月分表...

之前开发的一个监控系统,数据库的日志表是单表,虽然现在数据还不大并且做了查询sql优化,不过以后数据库的日志表数据肯定会越来越庞大,将会导致查询缓慢,所以把日志表改成分表,日志表可以按时间做水平分表,我是按月分的,每个月一张表,这时候的问题是

数据库有多张同样的分表如何根据条件查询?

在进行分页的时候如何计算总记录数?如何查询出所有分表?

每个月的新表是如何创建?系统如何自动创建?

不确定哪个分表的情况如何查询某一条详细记录?

b6cf07982362337234e7deefaed981b0.png

分表查询

分表查询可以用union或者union all进行查询

union和union all都是将两个结果集合 合并在一起

select * from log_2019_05 where createTime > '2019-05-01 10:00:00'

union all

select * from log_2019_06 where createTime < '2019-06-01 10:00:00'

在我们的java程序里面,根据用户的传的查询开始时间和结束时间,就可以解析出要查询那些表,然后拼接成我们要查的sql就可以了,举例:可以把要查的表放进数组里面,然后在mybatis的查询方法的xml里面循环遍历拼接出sql

注:

union去重且排序

union all不去重不排序

性能上union all较快,比union少了排序,union是把数据合并之后还会进行排序,在排序中去掉重复的

这里的日志表没有重复的,本身就是有时间顺序,所以用union all

计算分表的总记录数

如果想要一进列表页面的分页地方要显示出总记录数,可以查询出所有的分表,然后union all拼接后用count(*),那问题又来了,如何查询出所有同样结构的分表

想法一:我们这个分表是按月分,只要在程序获取当前年月份,以及我们最早创建的表年月份,就可以计算出所有的分表(最下面有计算两个日期之间的所有月份java代码)

想法二:按月分表,我们不一定要获取数据库所有分表的总记录数,可以在查询页面给一个开始时间默认值(可以默认当月1号也可以默认三个月前等),就统计这段时间的分表

想法三:如果我们的分表不是按月分的,那么又怎么知道所有的分表呢?这时候可以在mysql中可以用information_schema数据库的tables表查询出所有的分表记录

select table_name from INFORMATION_SCHEMA.TABLES where table_name like 'log_%'

6e451d6e81f8be0723ed59c1f58c9cc8.png

最后我采用的方案是查询页面的查询条件默认查询当前月,第一次进来日志列表页就显示当前月的分页数据,所以就不需要查询所有的分表(如果查询的时候选了开始结束时间,则计算出开始结束时间之间的所有月份,union all连接相应的月份表查询)

89da8f6f3ad8b732a461a4db0f4de8dc.png

information_schema.tables存储了数据表的元数据信息

information_schema数据库中的表都是只读的,不能进行更新、删除和插入等操作

按月的分表,每次要怎么创建

想法一:最简单的就是手动创建,自己手工创建接下来两年的

想法二:手动创建新表不能一劳永逸,肯定得程序自动创建才行,可以用定时任务,每个月1号执行一次,创建下个月的分表,或者每一段时间执行一次,创建接下来半年或者一两年的表(如果存在则不创建)

想法三:可以在程序的新增插入日志的时候判断一次当前月的表是否存在,不存在则创建后再插入数据

想法四:想法三可以但是表每个月只需创建一次,大多数都不需要判断,每次都判断是否存在有点多余且损耗性能,在这个基础上优化,用类似乐观锁的原理,每次插入数据的时候都认为已存在该表,直接插入,当抛出表不存在的异常时,捕获这个异常时新建表,然后再插入数据

如何查询分表的某一条详细记录

在列表页面看到只是日志的概略,还有详细的日志需要点击进去详细页面查看,问题来了,以前只需要传id参数就可以了,现在在分表中,每个表都有可能有相同的id,所以只穿一个id肯定不行的,这个时候需要再多穿一个创建时间参数,在程序里面根据这个创建时间就知道是那张分表了,然后再根据id查询即可。

注:

如果分表的id采用的是全局唯一ID的方案,所有的分表id都是不一样的,也是可以直接用ID查询出来的

计算两个日期之间的所有月份

/**

*

* @param minDate 最小时间

* @param maxDate 最大时间

* @return 日期集合 格式为 年-月

* @throws Exception

*/

public static List getMonthBetween(String minDate, String maxDate) throws Exception {

ArrayList result = new ArrayList();

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");//格式化为年月

SimpleDateFormat sdf2 = new SimpleDateFormat("yyyyMM");//格式化为年月

Calendar min = Calendar.getInstance();

Calendar max = Calendar.getInstance();

min.setTime(sdf.parse(minDate));

min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1);

max.setTime(sdf.parse(maxDate));

max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2);

Calendar curr = min;

while (curr.before(max)) {

result.add(sdf2.format(curr.getTime()));

curr.add(Calendar.MONTH, 1);

}

return result;

}

public static void main(String[] args) throws Exception{

String minDate = "2018-09-02 00:15:01";

String maxDate = "2019-06-02 00:15:01";

List list = DateUtils.getMonthBetween(minDate,maxDate);

for(String date :list){

System.out.println("时间:"+date);

}

}

运行main方法结果

dc5ab247a8d743c8caf7e9ed6e6dfed6.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值