[TEAP早期試讀]真正的好處:客戶端批量處理
圖靈社群按:
TEAP是什麼?TEAP是Turingbook Early Access Program的簡稱,即早期試讀,它公佈的是圖靈在途新書未經編輯的內容。一本書的翻譯週期約為3到6個月,如果在翻譯過程中,譯者就能與讀者進行溝通和交流,對整本書的翻譯品質是有幫助的。通過TEAP,讀者可以提前閱讀將來才能出版的內容,譯者也能收穫寶貴的反饋意見,改進翻譯,提高質量。本書原名為Expert PLSQL Practices,中文暫定名為《Oracle PL/SQL實戰》,本文選自第6章 批量SQL操作第7節
真正的好處:客戶端批量處理
正如我在本章開始時提到的,我反覆在五金店內折返降低了我的效率。不過,有時事情更糟糕得多:我支付了一個商品,開車回家,然後在車裡意識到我需要回去,然後開車回五金店,再購買別的東西。(為敏感的讀者著想,我不準備提及當發生這種情況時,我妻子使用的“鍾愛”一詞!)
本章描述了在PL/SQL中使用批量操作來訪問資料的效率,但這相當於已經在五金店裡。從外部的客戶端應用程式中訪問資料庫(網路往返),並採用一次一行的方式處理資料的代價相當於來回駕駛汽車去商店。這個代價是可以用一些簡單的演示量化的。
首先,我將構建(使用PL/SQL,當然!)許多用3GL程式碼實現的客戶端應用程式的一個副本,即一個程式在表上開啟一個遊標,而另一個程式一次獲取一行。下面是在bulk_network_1.sql中的程式碼:
SQL> create or replace
2 package PKG1 is
3
4 procedure open_cur(rc in out sys_refcursor);
5
6 procedure fetch_cur(rc in out sys_refcursor, p_row out hardware.item%type);
7
8 end;
9 /
Package created.
SQL> create or replace
2 package body PKG1 is
3
4 procedure open_cur(rc in out sys_refcursor) is
5 begin
6 open rc for select item from hardware;
7 end;
8
9 procedure fetch_cur(rc in out sys_refcursor, p_row out hardware.item%type) is
10 begin
11 fetch rc into p_row;
12 end;
13
14 end;
15 /
Package body created.
SQL Plus將足以作為客戶端應用程式呼叫這個包。當然SQL Plus本身即是一個真正的SQL客戶端,你能明確控制它每次獲取的行數這個屬性,所以上面的演示可以寫成這樣:
set arraysize n (n=1 for single row fetch, n=1000 for multirow fetch)
select item from HARDWARE;
但我想模擬3GL應用程式做的工作,即包含用顯式呼叫方式開啟遊標,再從它重複獲取,然後將其關閉。要開啟遊標,然後反覆獲取結果集,直到最後一行,我可以使用指令碼bulk_single_fetch_100000.sql,它執行以下步驟:
variable rc refcursor
exec pkg1.open_cur(:rc)
variable n number
exec pkg1.fetch_cur(:rc,:n);
exec pkg1.fetch_cur(:rc,:n);
[repeat 100000 times]
為了無需滾動100,000行輸出來檢視演示所消耗的時間,我關掉終端輸出並記錄之前和之後的時間戳。
SQL> variable rc refcursor
SQL> exec pkg1.open_cur(:rc)
SQL> select to_char(systimestamp,'HH24:MI:SS.FF') started from dual;
STARTED
------------------
12:11:18.779000
SQL> set termout off
SQL> @bulk_single_fetch_1000.sql -- 包含 1000 次獲取呼叫
[重複 100 次]
SQL> set termout on
SQL> select to_char(systimestamp,'HH24:MI:SS.FF') ended from dual;
ENDED
------------------
12:12:47.270000
你可以看到,100,000次到資料庫的往返大約用了90秒。我啟用會話跟蹤,再次執行演示並檢查TKPROF格式化後的結果檔案。下面是結果:
SELECT ITEM
FROM HARDWARE
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.05 0 1 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 100000 1.17 0.94 0 100003 0 100000
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 100002 1.17 1.00 0 100004 0 100000
可以看到,這90秒中,實際上花在資料庫工作上的只有一秒鐘。其他89秒的時間都用在網路來回跳躍上了。資料庫實際上是無所事事,而從客戶端應用程式的角度來看,它是在等待資料庫。用開車來打比方,我的車輪在轉動但哪兒也沒去。我目前的工作場所,每當我們中間層伺服器上遇到出現這種行為的3GL程式,我們稱之為“中介軟體失敗”。以這種方式來標識質量差的程式碼,確實能夠引起開發團隊的關注,效果好得出奇!
現在,讓我們採用這個新發現的批量處理方法從資料庫中批量獲取資料,並把資料批量地傳回客戶端。下面新實現的程式碼(bulk_network_2.sql)的效能會好很多:
SQL> create or replace
2 package PKG2 is
3
4 type t_num_list is table of hardware.item%type index by pls_integer;
5
6 procedure open_cur(rc in out sys_refcursor);
7
8 procedure fetch_cur(rc in out sys_refcursor, p_rows out t_num_list);
9
10 end;
11 /
Package created.
SQL> create or replace
2 package body PKG2 is
3
4 procedure open_cur(rc in out sys_refcursor) is
5 begin
6 open rc for select item from hardware;
7 end;
8
9 procedure fetch_cur(rc in out sys_refcursor, p_rows out t_num_list) is
10 begin
11 fetch rc bulk collect into p_rows limit 1000;
12 end;
13
14 end;
15 /
Package body created.
重新執行演示。每次將有1,000行被批量從資料庫中收集並傳回客戶端。由於SQL Plus本身並不理解返回來的陣列,資料將被簡單地追加到一個大的VARCHAR2變數(the_data)來模擬客戶端接收陣列的資料。這裡就是一個例子(bulk_multi_fetch_in_bulk.sql):
SQL> variable rc refcursor
SQL> exec pkg2.open_cur(:rc)
PL/SQL procedure successfully completed.
SQL> select to_char(systimestamp,'HH24:MI:SS.FF') started from dual;
STARTED
------------------
12:39:09.704000
SQL> variable the_data varchar2(4000);
SQL> set termout off
SQL> declare
2 n pkg2.t_num_list;
3 begin
4 :the_data := null;
5 pkg2.fetch_cur(:rc,n);
6 for i in 1 .. n.count loop
7 :the_data := :the_data||n(i);
8 end loop;
9 end;
[repeated 100 times]
SQL> select to_char(systimestamp,'HH24:MI:SS.FF') ended from dual;
ENDED
------------------
12:39:09.837000
差異是驚人的。週轉時間立即從90秒下降至0.13秒。
啟用跟蹤重新執行演示程式,跟蹤資訊揭示了在資料庫往返(次數)上的減少。
SELECT ITEM
FROM HARDWARE
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 100 0.04 0.04 0 256 0 100000
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 102 0.04 0.04 0 256 0 100000
演示程式仍然獲取了100,000行(最右列),但只呼叫了100次獲取。即使只有這個簡單的演示,它所展示的好處已經好得不能再好了。經常見到Oracle的客戶花費大筆資金,通過各種優化手段的實施,比如快取記憶體、建立索引、SQL調優等,或許能使得他們的系統效能得到額外的百分之10-15%的提高,有時候,客戶甚至購買更多的硬體,並支付增加的相關許可證費用。但考慮本演示中的獲得的效能好處:
從90秒到0.13秒,幾乎提高了700倍。
作為應用程式開發人員,如果你修改程式碼,使(程式)速度快上幾百倍,那將會使你的應用更加成功,而你更受歡迎!能否降低一個客戶端應用程式與資料庫互動中的網路往返次數,很大程度上取決於開發人員對他們的客戶程式所用語言工具的運用能力,應用的設計是否能夠充分利用一種智慧的方式將資料傳遞到資料庫,還有開發人員的努力。但作為一個資料庫開發人員,如果你能確保你的PL/SQL到資料庫的介面都配備允許客戶端應用程式傳遞和接收大容量資料(的功能),那麼你更接近實現良好的應用程式效能。
相關文章
- 第十八篇:批量處理情況下的回射客戶端客戶端
- [TEAP早期試讀]《敏捷武士》推薦序敏捷
- python socketserver處理客戶端的流程PythonServer客戶端
- Redis 是如何處理命令的(客戶端)Redis客戶端
- Kafka 處理器客戶端介紹Kafka客戶端
- [TEAP早期試讀]HTML5與JSONHTMLJSON
- [TEAP早期試讀]敏捷武士之敏捷簡介敏捷
- 以客戶端為中心的錯誤處理客戶端
- ZooKeeper客戶端事件序列化處理客戶端事件
- [TEAP早期試讀]《程式設計師的數學》- 前言程式設計師
- [TEAP早期試讀]資料庫和敏捷開發資料庫敏捷
- nginx 處理客戶端請求的完整過程Nginx客戶端
- 專案分享九:客戶端的異常處理客戶端
- [TEAP早期試讀]基於WebSocket的聯機作圖例子Web
- [TEAP早期試讀]NoSQL資料庫的基礎知識SQL資料庫
- [TEAP早期試讀]《深入淺出CoffeeScript》譯者序
- [TEAP早期試讀]《MongoDB in Action》——為什麼選擇MongoDB?MongoDB
- [TEAP早期試讀]《深入淺出CoffeeScript》CoffeeScript中的OOPOOP
- [TEAP早期試讀]Linux: 一個人加上一百萬人的智慧Linux
- 網路傳輸時間和客戶端處理時間的界定(批處理應用)客戶端
- 對客戶又是供應商的客戶清賬處理
- 微前端:DDD和微服務對客戶端開發的好處 - thenewstack前端微服務客戶端
- [TEAP早期試讀]Android開發實現後臺下載Android
- [TEAP早期試讀]《程式設計師的數學》- 邏輯工具卡諾圖程式設計師
- CRM客戶管理系統有哪些好處
- 客戶預付款處理和設定
- Redis處理客戶端連線的內部實現機制RXRedis客戶端
- [TEAP早期試讀]《深入淺出CoffeeScript》CoffeeScript與Node.jsNode.js
- 如果呼叫遠端遠端url介面為https,且存在客戶端證書驗證,如何在客戶端處理HTTP客戶端
- 客戶端無法同步時間伺服器問題處理客戶端伺服器
- [TEAP早期試讀]《Linux/Unix設計思想》之: 大教堂?多怪異Linux
- 處理客戶小機問題[一則]
- [TEAP早期試讀]《30天寫出你的作業系統》 - 挑戰多工作業系統
- 傳奇原始碼分析-客戶端(遊戲邏輯處理源分析二)原始碼客戶端遊戲
- PostgreSQL客戶端處理事務功能詳解EGSQL客戶端
- 記筆記:C# Socket客戶端監聽伺服器端處理方案【同步】筆記C#客戶端伺服器
- MySQL使用Batch批量處理MySqlBAT
- kickstart之批量安裝puppet客戶端客戶端