數據量大的表的分表方案 以及 跨(同類型的)表查詢遇上分組時需要注意的點

最近着手對數據量比較大的表的改善工作。當一張表的數據量很大,並且在定時或實時的增加數據時,這時候就需要考慮表的容量,因爲一張表的數據不可能無限大,所以考慮分表就迫在眉睫~~

 

解決方案:

1)結合表內數據的Insert頻率,大概計算下表數據的大小。規劃每張表最大的數據量,考慮按年或月或天分表,表名基本相同,以時間字符串作爲後綴(如:表名_yyyy,表名_yyyyMM,表名_yyyyMMdd等);

2)假如最小維度的表的每條記錄是按分鐘入的(總之不是天),時間字段爲“yyyyMMdd”格式(即“天”)。那麼要求出一段時間的(哪天到哪天)按天分組的統計結果,直接查詢該最小維度的表即可。

若該表是按天分開存儲,需考慮跨表的情形,關於跨表的思想見我前一篇文章;

3)假如需要查詢一段時間(哪月到哪月)的按“月”分組統計的情況,則不再建議直接查詢最小維度的表,因爲既要考慮分表,而且union all的表的數量太多,造成卡死,效率上不太現實。

——解決:定時任務每月初去統計上一個月的總體情況,時間字段爲"yyyyMM"格式(即“月”),如最小維度的表是按月存儲的,則讀取上一個月的彙總情況,成爲一條記錄,該條記錄即是上一個月的總體情況,專門存入一張如“表名_month”的表中,此時,不必實時去最小維度的表彙總,直接讀取該month表就行啦;

4)假如需要查詢一段時間(哪年到哪年)的按“年”分組統計的情況,同上,可在"表名_month"表中,在月維度的數據基礎上彙總,存儲在"表名_year"表中,此時這張year的表的每一條記錄代表一個“年”的總體情況,時間字段爲"yyyy"格式(即“年”),此時直接讀取"表名_year"表即可。

5)在按月和按年定時彙總數據到相應維度的表的同時,也要建立下一個月的月表或下一年的年表。

 

接下來要講的是同類型的表遇上分組時需要注意的地方,現假設有2張表itm_test和itm_test2,他們的時間字段爲app,按探討的背景,這2張表的app字段的值肯定是不會重複的。。

這2張表的數據情況如下:

itm_test表:



 itm_test2表:



 (現在假設app爲時間字段。。這2張表的時間字段的值是不會重複的……)

 

情形一:按單個字段分組,這個字段非時間字段app。

寫法一(2張表都group by之後再union all,並且查詢條件分散在每張表):

 

(SELECT src,SUM(cnt) FROM itm_test WHERE app>'app2' GROUP BY src ORDER BY src) 
UNION ALL (SELECT src,SUM(cnt) FROM itm_test2 WHERE app<'app7' GROUP BY src ORDER BY src)

 查詢結果:



 寫法二(2張表先union all之後再group by,並且查詢條件分散在每張表):

 

SELECT src, SUM(cnt) FROM ((SELECT * FROM itm_test WHERE app>'app2') UNION ALL (SELECT * FROM itm_test2 WHERE app<'app7')) tmp GROUP BY src ORDER BY src

 查詢結果:



 
 

寫法三(2張表先union all之後再group by,並且查詢條件在union all之後的臨時表裏):

 

SELECT src,SUM(cnt) FROM((SELECT  * FROM itm_test) UNION ALL (SELECT * FROM itm_test2 ) tmp 
  WHERE app > 'app2' AND app < 'app7' GROUP BY src ORDER BY src 

 查詢結果:



 

綜上:寫法一是錯誤的,因爲原意是要統計一段時間內按src的cnt的彙總,但是寫法一卻有2條nbk5,即2個src相同的記錄,這是違背初衷的。

 

情形二:按多個字段分組,其中一個字段包含時間字段app。

寫法一(2張表都group by之後再union all,並且查詢條件分散在每張表

 

(SELECT app,src,SUM(cnt) FROM itm_test WHERE app>'app2' GROUP BY app,src ORDER BY app,src ) 
UNION ALL (SELECT app,src,SUM(cnt) FROM itm_test2 WHERE app<'app7' GROUP BY app,src ORDER BY app,src )

 寫法二(2張表先union all之後再group by,並且查詢條件分散在每張表)

 

SELECT app,src, SUM(cnt) FROM ((SELECT * FROM itm_test WHERE app>'app2') UNION ALL (SELECT * FROM itm_test2 WHERE app<'app7')) tmp GROUP BY app,src ORDER BY app,src

 寫法三(2張表先union all之後再group by,並且查詢條件在union all之後的臨時表裏):

 

SELECT app,src,SUM(cnt) FROM((SELECT  * FROM itm_test) UNION ALL (SELECT * FROM itm_test2 ) tmp 
  WHERE app > 'app2' AND app < 'app7' GROUP BY src ORDER BY app,src 

 三種寫法都是同樣的查詢結果:



 綜上,此時是按多個字段分組統計的,並且其中有個字段是app(時間字段),三種寫法都是等效的。

 

所以,當跨同類型的表查詢遇上分組統計時,需要看時間字段是否在group by的條件當中:如果在,三種寫法都是等效的,如果不在,寫法一是錯誤的。查詢條件不管是分散在每張表中還是集中在臨時表中,都是一樣的。臨時表需要加上表別名,否則報錯:

Every derived table must have its own alias

  • 81b14aaa-277b-3940-9961-d3c0c22afd35-thumb.png
  • 大小: 6.9 KB
  • 63ebd090-b5dc-3da0-8454-284080080721-thumb.png
  • 大小: 7.3 KB
  • 20b3a357-1fad-3ec2-b3ff-afd0d2a7310d-thumb.png
  • 大小: 3.6 KB
  • fd880dfb-beba-3540-a170-b94d615e9a49-thumb.png
  • 大小: 3.5 KB
  • 1f2e830c-fdc6-378f-b5b8-3b1e61e8930e-thumb.png
  • 大小: 3.7 KB
  • a36fa025-8e09-36b3-9a43-99d6994ac601-thumb.png
  • 大小: 6.4 KB
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章