問題:
注意:這里說的不是【分庫分表】里的分表,而是將一個大表的某些字段拆分到別的表里
一個論壇系統,有兩個頁面,一個是帖子基本信息列表頁面,一個是展示某個帖子的詳細內容頁面。現在可以在一張表A中,同時存儲帖子的基本信息和詳細內容。
1、后來發現,帖子的數量多了,帖子列表頁面的加載速度明顯慢了很多。這是為什么?
2、是不是說將表A拆分成兩張一對一關聯的表,一張表只放基本信息,用來加載帖子列表頁面;另一張表只放詳細內容,在查詢的時候也只是查單張表,不會影響效率?
解決過程:
想了想,搜了搜,才發現自己真的是二了。
1、我只是用到了某些基本信息字段(比如標題等),但是查詢的時候卻查了所有的字段,其中單content列的數據就十分龐大,速度自然就慢了。所以查詢的字段越多,查詢的速度越慢。
下圖,可以看到兩條sql語句的查詢時間:
2、可以將表拆成一對一關聯的表,但這是表設計方面的問題了,現在數據已經很多了,調整數據結構太復雜了。
那么根據“hibernate查詢部分字段值,比查詢所有字段值效率高”的原理,如上圖那樣,查詢的時候,只查部分數據,是不是也可以呢?
興致勃勃得嘗試了以后,才發現自己太天真了
以下是我更改后的查詢方法:
//String hql="from Topic where top=1";
String hql="select id,modifyTime,publishTime,title,good,top,replySum,remark,firstimg,section,user from Topic where top=1"); Query query = em.createQuery(hql); List<Topic> result = query.getResultList();
結果報錯:java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to forum.po.Topic
類型轉換出錯。調試發現,只有部分字段數據根本不能轉換成真正的對象,最后頁面調用的時候,自然會出錯。
后來研究“hibernate是如何把查詢結果轉換為對象的”,感覺只取查詢結果中的一部分值到對象里並不容易。
最后還是更改了數據庫和實體類:
將帖子的基本信息,和帖子的詳細內容分成兩張表A、B存儲。
剛開始使用@OneToOne關聯映射,懶加載。仍然報錯,懶加載沒有加載到。
后來,我就決定不使用OneToOne了,而是手動定義詳細內容表B中的一列為基本信息表A中的主鍵。只是增加、刪除的時候需要多考慮一張表。
結果:頁面加載速度也快了,問題解決。
分析:使用@OneToOne關聯,就必須定義外鍵了,在查詢的時候懶加載,可能加載不到外鍵的數據,所以頁面中也獲取不到
后來分成的A、B兩張表,並沒有定義外鍵關聯,只是有B表的一列表示A表的主鍵。這樣的話,兩張表之間是完全沒有關聯的,可以單獨查詢。麻煩的是在增刪的時候,要在代碼中控制一起創建(A先B后),或者一起刪除(先后無所謂)。
原創文章,歡迎轉載,轉載請注明出處!