mysql如何查詢多樣同樣的表/sql分表查詢、java項目日志表分表的開發思路/按月分表


之前開發的一個監控系統,數據庫的日志表是單表,雖然現在數據還不大並且做了查詢sql優化,不過以后數據庫的日志表數據肯定會越來越龐大,將會導致查詢緩慢,所以把日志表改成分表,日志表可以按時間做水平分表,我是按月分的,每個月一張表,這時候的問題是

  1. 數據庫有多張同樣的分表如何根據條件查詢?
  2. 在進行分頁的時候如何計算總記錄數?如何查詢出所有分表?
  3. 每個月的新表是如何創建?系統如何自動創建?
  4. 不確定哪個分表的情況如何查詢某一條詳細記錄?
    在這里插入圖片描述

分表查詢
分表查詢可以用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(*),那問題又來了,如何查詢出所有同樣結構的分表

  1. 想法一:我們這個分表是按月分,只要在程序獲取當前年月份,以及我們最早創建的表年月份,就可以計算出所有的分表(最下面有計算兩個日期之間的所有月份java代碼)
  2. 想法二:按月分表,我們不一定要獲取數據庫所有分表的總記錄數,可以在查詢頁面給一個開始時間默認值(可以默認當月1號也可以默認三個月前等),就統計這段時間的分表
  3. 想法三:如果我們的分表不是按月分的,那么又怎么知道所有的分表呢?這時候可以在mysql中可以用information_schema數據庫的tables表查詢出所有的分表記錄
select table_name from INFORMATION_SCHEMA.TABLES where table_name like 'log_%' 

在這里插入圖片描述
最后我采用的方案是查詢頁面的查詢條件默認查詢當前月,第一次進來日志列表頁就顯示當前月的分頁數據,所以就不需要查詢所有的分表(如果查詢的時候選了開始結束時間,則計算出開始結束時間之間的所有月份,union all連接相應的月份表查詢)
在這里插入圖片描述


information_schema.tables存儲了數據表的元數據信息
information_schema數據庫中的表都是只讀的,不能進行更新、刪除和插入等操作

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

  1. 想法一:最簡單的就是手動創建,自己手工創建接下來兩年的
  2. 想法二:手動創建新表不能一勞永逸,肯定得程序自動創建才行,可以用定時任務,每個月1號執行一次,創建下個月的分表,或者每一段時間執行一次,創建接下來半年或者一兩年的表(如果存在則不創建)
  3. 想法三:可以在程序的新增插入日志的時候判斷一次當前月的表是否存在,不存在則創建后再插入數據
  4. 想法四:想法三可以但是表每個月只需創建一次,大多數都不需要判斷,每次都判斷是否存在有點多余且損耗性能,在這個基礎上優化,用類似樂觀鎖的原理,每次插入數據的時候都認為已存在該表,直接插入,當拋出表不存在的異常時,捕獲這個異常時新建表,然后再插入數據

如何查詢分表的某一條詳細記錄
在列表頁面看到只是日志的概略,還有詳細的日志需要點擊進去詳細頁面查看,問題來了,以前只需要傳id參數就可以了,現在在分表中,每個表都有可能有相同的id,所以只穿一個id肯定不行的,這個時候需要再多穿一個創建時間參數,在程序里面根據這個創建時間就知道是那張分表了,然后再根據id查詢即可。

注:
如果分表的id采用的是全局唯一ID的方案,所有的分表id都是不一樣的,也是可以直接用ID查詢出來的

計算兩個日期之間的所有月份

    /** * * @param minDate 最小時間 * @param maxDate 最大時間 * @return 日期集合 格式為 年-月 * @throws Exception */ public static List<String> getMonthBetween(String minDate, String maxDate) throws Exception { ArrayList<String> result = new ArrayList<String>(); 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<String> list = DateUtils.getMonthBetween(minDate,maxDate); for(String date :list){ System.out.println("時間:"+date); } } 

運行main方法結果
在這里插入圖片描述

 

 

原文鏈接:https://www.csdn.net/gather_20/MtTaUg3sODk3OC1ibG9n.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM