1. 程式人生 > >大資料量實時統計排序分頁查詢 優化總結

大資料量實時統計排序分頁查詢 優化總結

大資料量實時統計排序分頁查詢(併發數較小時)  的瓶頸不是函式(count,sum等)執行,

不是having, 也不是order by,甚至不是表join, 導致慢的原因就在於“資料量太大本身”

  1. 化整為零

就是將表劃分為M份相互獨立的部分,可以是分表,也可以是不分表但冗餘一個取模結果欄位

實際結果是不分表比分表更加靈活,只需稍加配置,就可以動態切分大表,隨意更改M的大小。

將1條慢sql(大於30秒)拆分成為N條查詢速度巨快的sql(單條sql執行時間控制在20毫秒以內)

然後再web應用中以適當的執行緒數去併發查詢這些執行時間快的N條小sql再彙總結果

  1. 兩步查詢

第一步查詢中去併發執行這N條小sql, 只取排序欄位和標識欄位,其他欄位一律丟棄

彙總結果後定位出當前頁面要顯示的pageNum條資料,再進行第二步查詢,取出頁面上需要展示的所有欄位

  1. web應用自身計算與資料庫計算的折中

PS:這一點是至關重要的,其他幾點都可以不看,這點是最關鍵的。慢慢解釋一下:

有三種方式統計所有的記錄,

a)         第一種方式是把資料庫中所有記錄(只取排序欄位和標識欄位並且不做任何sum,count having order by等操作)

全部拉到web應用中,在web應用中完成所有的計算

b)         第二種方式是把資料庫中所有記錄做sum count having等操作之後的所有行數拉到web應用中,在web應用中完成剩餘計算

c)         第三種方式是把資料庫中所有記錄做sum count having order by等操作之後把limit後的資料拉到web應用中,

在web應用中對limit後的資料再計算

顯然,第一種方式 資料庫什麼活都不做只取資料 是不可行的。以lg_order_count_seller為例,1500萬行,

如果只算id, seller_id和order_count 這三個bigint型別,至少需要拉8*3*1500 0000 = 360000000=340M,

拉到記憶體中之後儲存需要8*4*15000000= 460M,這還不算List是的2的n次方這個特點和計算排序等的記憶體開銷,

不僅資料庫與web應用機器IO扛不住,就是應用自身恐怕也要OOM了。

第二種方式,所有記錄做sum count having等操作之後,由於是group by seller_id的,總得資料量變為100萬(就是賣家總數),

這樣子一來,共需要拉8*3*100 0000 = 23M,拉到記憶體之後,需要8*4*100 0000 = 30M, 再算上List是的2的n次方這個特點和

計算排序等的記憶體開銷也不會超過100M, IO的時間和記憶體開銷勉強可以考慮接受。

第三種方式,所有記錄做sum count having order by等操作之後把limit後的資料拉到web應用中,因為做了limit,所以,

資料量很小了,無論是IO還是記憶體開銷都已經很小了。可以忽略。

綜合以上三種,第三種方式適用於頁面的前n頁和後n頁,因為這個limit的資料量隨著頁數的增大而增大,

當大到每個切分後的小表的資料量時就轉為第二種方式了。

第二種方式適用於頁面的第[n+1, totaoPageNum-n]頁。

  1. 切分成N條小sql後並行執行時排序不穩定性的解決辦法

① 問題描述:

優化之前,還是是一條大慢sql查詢時,由於資料庫排序是穩定排序,

所以當兩條記錄排序欄位值相同時他們在頁面上的頁碼位置是固定的。

優化之後,當並行執行這N條小sql時,由於無法控制這些小sql的先後執行順序,

導致在web應用中當兩條記錄的排序欄位值相同時在頁面上的頁碼位置是隨機的。

② 解決辦法:

除了拉標識欄位(seller_id)和排序欄位(order_count_sum)之外,再取一個unique(id)的欄位,當兩條記錄的排序欄位值相同時,

再用這個unique的欄位(在賣家監控中這個欄位是id)進行第二次排序.這樣就解決了排序不穩定的問題。

③ 也許,看到這裡會有疑問,為什麼不用seller_id?seller_id也是唯一, 這樣子不是少取id這個欄位,減少IO了?

seller_id雖然也是唯一,可以輔助排序,但是不要忘記資料庫的排序規則是:

如果兩列的值相等,那麼序號在前的排在前面,這裡的序號就是主鍵(自動生成,autoincrement),

如果用seller_id的話還是不能保證排序的穩定性,只能用主鍵id.

  1. 優先載入頁面上的主要元素,然後再去非同步載入次要元素,

把資料庫的連線,掃表,計算等資源優先讓給使用者關注的主要元素,次要元素可等主要元素載入完成之後再載入。

反應在賣家監控頁面中,查資料和查頁頁碼的sql語句基本相同,是在競爭同一資源,

所以,需要做一個策略,優先把資源讓給查數,資料查完之後再去查頁碼。

  1. 限流

由於多執行緒取資料並沒有從本質上提高資料庫效能,所以必須針對大資料量實時統計排序分頁查詢做限流

我這裡打個比方:食堂有6個視窗,物流團隊吃飯要買6個菜,平均每買1個菜需要1分鐘的時間,

如果派我一個人去一個視窗買的話需要6分鐘的時間

假如派6個人分別去6個視窗買這6個菜,只需要1分鐘的時間

但是,如果除了物流團隊,再來其他5個團隊呢,也就是說6個團隊每個團隊買6個菜共買36個菜,

這樣子有的團隊先買完,有的團隊後買完,但平均時間還是6分鐘。本質上沒有變化。

   所以,對於特定的查詢條件,必須進行限流。讓每分鐘至多有6個團隊買菜,這樣子能使得情況變得不至於太糟糕。

  1. 從根本上改變現狀

這一點從目前來看只能是展望了,比如mysql資料庫換更為強大的oracle資料庫,

或更換InnoDb引擎為其他,或更換SATA硬碟為SSD 。。。。。。

  1. 從實踐效果來看,優化後的效果是很明顯的。

相同的查詢條件,原來一個頁面查詢時間由於超過60秒超時了,根據1-6點建議優化之後,查詢時間變為2秒至3.5秒之間。

相關推薦

料量實時統計排序查詢 優化總結

大資料量實時統計排序分頁查詢(併發數較小時)  的瓶頸不是函式(count,sum等)執行, 不是having, 也不是order by,甚至不是表join, 導致慢的原因就在於“資料量太大本身” 化整為零 就是將表劃分為M份相互獨立的部分,可以是分表,也可以是不分表

請求料量介面時手動

前段時間做專案遇到這麼種情況,需要呼叫一個批量查詢介面,GET請求的 ,比如根據使用者id批量查詢使用者資訊的,介面提供方提供的就是GET請求的,然而我們一次要查詢幾萬個使用者,這樣請求的結果就是介面直接掛掉,因為GET請求沒法傳遞那麼多資料,最後的解決方案是人為地進行分頁

Oracle (05)外來鍵約束.序列.索引.檢視.查詢技術.排序查詢.資料庫表格設計正規化

外來鍵約束 (完整性約束)(fk) ***** 牽扯到兩個表格: 概念: 1. 外來鍵約束, 是存在兩個表格的操作 ! 2. 一張表格我們稱為主表(父表) , 另一張叫做從表(子表) , 定義了外來鍵約束的表格屬於從表 ! 3. 從表的外來鍵欄位, 是在參考主表中的主鍵

料量下的SQL Server資料庫自身優化

原文: http://www.d1net.com/bigdata/news/284983.html 1.1:增加次資料檔案          從SQL SERVER 2005開始,資料庫不預設生成NDF資料檔案,一般情況下有一個主資料檔案(MDF)就夠了,但是有些大型的資

根據時間排序查詢導致部分資料丟失原因

場景:根據時間排序分頁查詢交易記錄表時,查總數沒問題,但是從一頁到下一頁的時候,在每頁分隔的地方可能會出現記錄部分丟失。分析:SELECT id, orderNo, addTime FROM deal_

oracle排序查詢與不排序

oracle分頁有通用寫法,假設一頁5行select * from ( select t.,rownum from ( select from table1 where condition order by column) t ) where rownum&g

MySQL查詢優化

插入 hist shel 使用範圍 表優化 方便 歷史 生成器 速度 當需要從數據庫查詢的表有上萬條記錄的時候,一次性查詢所有結果會變得很慢,特別是隨著數據量的增加特別明顯,這時需要使用分頁查詢。對於數據庫分頁查詢,也有很多種方法和優化的點。下面簡單說一下我知道的一些方法。

mysql查詢優化(索引延遲關聯)

對於web後臺報表匯出是一種常見的功能點,實際對應服務後端即資料庫的排序分頁查詢。如下示例為公司商戶積分報表匯出其中一個sql ,當大批量的匯出請求進入時候,mysql的cpu急劇上升瞬間有拖垮庫的風險。 SELECT * FROM coupons.cp_score_log WHERE

MySQL語句執行優化查詢優化,分庫表(一)

下面是關於在使用SQL時,我們儘量應該遵守的規則,這樣可以避免寫出執行效率低的SQL 1、當只需要一條資料時,使用limit 1      在我們執行查詢時,如果添加了 Limit 1,那麼在查詢的時候,在篩選到一條資料時就會停止繼續查詢,但是如果沒有新增limit 1即

mysql5.6 查詢優化

mysql5.6 分頁查詢優化 場景: 表結構:主鍵(非自增)contentCode(varchar),過濾條件列為upda

Sybase 料量(100W條) jdbc實現目前要求無排序

首次分頁大概為10秒左右。以後翻頁基本上是瞬間完成。要求是無排序情況下。 分析:sybase不提供分頁方法。top函式還不能放在子查詢語句中。使用hibernate分頁前幾頁和後幾頁沒問題,如果資料量大翻到30000頁時就記憶體溢位了。而且效率慢。 使用儲存過程分

料量 Mybatis 外掛Count語句優化

前言 當在大數量的情況下,進行分頁查詢,統計總數時,會自動count一次,這個語句是在我們的查詢語句的基礎上巢狀一層,如: SELECT COUNT(*) FROM (主sql) 這樣在資料量大的情況下,會出問題,很容易cpu就跑滿了 優化 在mapper.xml

MySQL料量查詢方法及其優化 MySQL料量查詢方法及其優化

MySQL大資料量分頁查詢方法及其優化   ---方法1: 直接使用資料庫提供的SQL語句---語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N ---適應場景: 適用於資料量較少的情況(元組百/千級) --

解決mongodb料量查詢效率問題

最常見的分頁採用的是skip+limit這種組合方式,這種方式對付小資料倒也可以,但是對付上幾百上千萬的大資料,只能力不從心,skip如果跳過大量的資料會很慢,並且會越查越慢,針對這一情況,可以通過條件查詢+排序+限制返回記錄,即 邊查詢,邊排序,排序之後,抽取上一頁中的最後一條記錄,作為當前分

mongodb料量查詢效率問題

最常見的分頁採用的是skip+limit這種組合方式,這種方式對付小資料倒也可以,但是對付上幾百上千萬的大資料,只能力不從心,skip如果跳過大量的資料會很慢,並且會越查越慢。 //程式碼大概看下意思就行了 const list = db.getCollection('se

MySQL料量查詢方法及其優化 ---方法1: 直接使用資料庫提供的SQL語句 ---語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N ---適

測試實驗 1.   直接用limit start, count分頁語句, 也是我程式中用的方法: select * from product limit start, count 當起始頁較小時,查詢沒有效能問題,我們分別看下從10, 100, 1000, 10000開始分頁的執行時間(每頁取20條), 如

採用Kettle處理料量抽取任務

需求: 將Oracle資料庫中某張表歷史資料匯入MySQL的一張表裡面。 源表(Oracle):table1 目標表(MySQL):table2 資料量:20,000,000         思路: 由於伺服器記憶體

MySql SQL 料量limit替代和優化(試驗)

select SQL_NO_CACHE u.id, u.user_id, u.user_name, u.user_name_index, u.email, u.pwd, u.email_token, u.email_active_date, u.

mysql 料量優化

假設有一個千萬量級的表,取1到10條資料; select * from table limit 0,10; select * from table limit 1000,10; 這兩條語句查詢時間應該在毫秒級完成; select * from table limit

mysql limit做查詢優化料量

mysql limit查詢優化,由於limit經常用到,卻沒有注意,因為平時做的專案都比較小,所以也沒有考慮去怎麼優化,MYSQL的優化是非常重要的。其他最常用也最需要優化的就是limit。mysql的limit給分頁帶來了極大的方便,但資料量一大的時候,limit的效能就急