上億資料如何秒查

2021-10-23 14:16:47 字數 3786 閱讀 7163

實戰:上億資料如何秒查

最近在忙著優化集團公司的乙個報表。優化完成後,報表查詢速度有從半小時以上(甚至查不出)到秒查的質變。從修改sql查詢語句邏輯到決定建立儲存過程實現,花了我3天多的時間,在此總結一下,希望對朋友們有幫助。

資料背景

首先專案是西門子中國在我司實施部署的mes專案,由於專案是在產線上運作(3 years+),資料累積很大。在專案的資料庫中,大概上億條資料的表有5個以上,千萬級資料的表10個以上,百萬級資料的表,很多…

(歷史問題,當初實施無人監管,無人監控資料庫這塊的效能問題。ps:我剛入職不久…)

不多說,直接貼西門子中國的開發人員在我司開發的ssrs報表中的sql語句:

select distinct b.materialid as matl_def_id, c.descript, case when right(b.mesorderid, 12) < 『001000000000』 then right(b.mesorderid, 9)

else right(b.mesorderid, 12) end as pom_order_id, a.lotname, a.sourcelotname as comlot,

e.defid as commaterials, e.descript as commatdes, d.vendorid, d.datecode,d.snnote, b.onplantid,a.sncust

from

(select m.lotname, m.sourcelotname, m.opetypeid, m.operationdate,n.sncust from view1 m

left join co_sn_link_customer as n on n.snmes=m.lotname

where

( m.lotname in (select val from fn_string_to_table(@sn,』,』,1)) or (@sn) = 『』) and

( m.sourcelotname in (select val from fn_string_to_table(@batchid,』,』,1)) or (@batchid) = 『』)

and (n.sncust like 『%』+ @sn_ext + 『%』 or (@sn_ext)=』』)

) aleft join

(select * from table1 where sntype = 『intsn』

and snrulename = 『productsnrule』

and onplantid=@onplant

) b on b.sn = a.lotname

inner join mmdefinitions as c on c.defid = b.materialid

left join table1 as d on d.sn = a.sourcelotname

inner join mmdefinitions as e on e.defid = d.materialid

where not exists (

select distinct lotname, sourcelotname from elcv_assemble_ops

where lotname = a.sourcelotname and sourcelotname = a.lotname

)and (d.datecode in (select val from fn_string_to_table(@dcode,』,』,1)) or (@dcode) = 『』)

and (d.snnote like 『%』+@snnote+』%』 or (@snnote) = 『』)

and ((case when right(b.mesorderid, 12) < 『001000000000』 then right(b.mesorderid, 9)

else right(b.mesorderid, 12) end) in (select val from fn_string_to_table(@order_id,』,』,1)) or (@order_id) = 『』)

and (e.defid in (select val from fn_string_to_table(@comdef,』,』,1)) or (@comdef) = 『』)

–view1是乙個巢狀兩層的檢視(出於保密性,實際名稱可能不同),裡面有一張上億資料的表和幾張千萬級資料的表做左連線查詢

–table1是乙個資料記錄超過1500萬的表

這個查詢語句,實際上通過我的檢測和調查,在b/s系統前端已無法查出結果,半小時,一小時 … 。因為我直接在sql查詢分析器查,半小時都沒有結果。

(原因是裡面對一張上億級資料表和3張千萬級資料表做全表掃瞄查詢)

不由感慨,西門子中國的素質(或者說責任感)就這樣?

下面說說我的分析和走的彎路(思維誤區),希望對你也有警醒。

探索和誤區

首先相關表的索引,沒有建全的,把索引給建上。

索引這步完成後,發現情況還是一樣,查詢速度幾乎沒有改善。後來想起相關千萬級資料以上的表,都還沒有建立表分割槽。於是考慮建立表分割槽以及資料複製的方案。

這裡有必要說明下:我司報表用的是乙個專門的資料庫伺服器,資料從產線訂閱而來。就是常說的「讀寫分離」。

如果直接在原表上建立表分割槽,你會發現執行表分割槽的事物會直接死鎖。原因是:表分割槽操作本身會鎖表,產線還在推資料過來,這樣很容易「阻塞」,「死鎖」。

我想好的方案是:建立乙個新錶(空表),在新表上建好表分割槽,然後複製資料過來。

正打算這麼幹。等等!我好像進入了乙個嚴重的誤區!

分析:原sql語句和業務需求,是對產線的資料做產品以及序列號的追溯,關鍵是查詢條件裡沒有有規律的」條件」(如日期、編號),

貿然做了表分割槽,在這裡幾乎沒有意義!反而會降低查詢效能!

一. 對原sql語句的分析

查詢語句的where條件,有大量@var in … or (@var =」) 的片段

where條件有like 『%』+@var+』%』

where條件有 case … end 函式

多次連線同一表查詢,另外使用本身已巢狀的檢視表,是不是必須,是否可替代?

sql語句有號,檢視中也有號出現

二. 優化設計

首先是用儲存過程改寫,好處是設計靈活。

核心思想是:用乙個或多個查詢條件(查詢條件要求至少輸入乙個)得到臨時表,每個查詢條件如果查到集合,就更新這張臨時表,最後彙總的時候,只需判斷這個臨時表是否有值。以此類推,可以建立多個臨時表,將查詢條件彙總。

這樣做目前來看至少兩點好處:

省去了對變數進行 =@var or (@var=」)的判斷;

拋棄sql拼接,提高**可讀性。

再有就是在書寫儲存過程,這個過程中要注意:

盡量想辦法使用臨時表掃瞄替代全表掃瞄;

拋棄in和not in語句,使用exists和not exists替代;

和客戶確認,模糊查詢是否有必要,如沒有必要,去掉like語句;

注意建立適當的,符合場景的索引;

踩死 「*」 號;

避免在where條件中對字段進行函式操作;

對實時性要求不高的報表,允許髒讀(with(nolock))。

三. 儲存過程

雖然犧牲了**的可讀性,但創造了效能價值。本人水平有限,還請各位不吝賜教!

最後,將ssrs報表替換成此儲存過程後,sql查詢分析器是秒查的。b/s前端用時1~2秒!

四. 總結

平常的你是否偶爾會因急於完成任務而書寫一堆效能極低的sql語句呢?寫出可靠性能的sql語句不難,難的是習慣。

耗時3天,上億資料如何做到秒級查詢?

最近在忙著優化集團公司的乙個報表。優化完成後,報表查詢速度由從半小時以上 甚至查不出 到秒查的質變。從修改 sql 查詢語句邏輯到決定建立儲存過程實現,花了我 3 天多的時間,在此總結一下,希望對朋友們有幫助。資料背景 首先專案是西門子中國在我司實施部署的 mes 專案,由於專案是在產線上運作 3 ...

高效率批量插入上億資料

轉至 create table create table tmp test chas lee f01 varchar2 20 f02 number 10 not null,f03 varchar2 21 f04 varchar2 21 f05 number,f06 number 20 建立乙個臨時表...

如何遍歷資料夾下上億檔案而不棧溢位

序 乙個資料夾下面有很多層的小檔案,如何算出這個資料夾下面有多少檔案?遞迴遍歷,簡單暴力,遞迴在一般情況確實是比較方便的解決方案,但是當資料夾深度多深,遞迴的反覆呼叫會導致方法一直無法釋放,造成jvm的棧溢位。那我們該怎麼辦?原文和作者一起討論 說實話這個問題我以前也沒有遇到過,我是聽一位我很敬佩的...