以下的簡略模式是一種可行的實(shí)現(xiàn)。
圖2 針對不同病人的對象類規(guī)范化的物理模式例子
應(yīng)用程序開發(fā)人員的問題是病人信息很可能使用不同的應(yīng)用程序輸入,或同一應(yīng)用程序中不同的屏幕因?yàn)樾枰煌墓ぷ髁鞒虂硗耆浫氡匾牟∪诵畔?。作為對象模型,開發(fā)人員更容易從“patient”父類中抽取出住院或門診病人,等到將數(shù)據(jù)保存至數(shù)據(jù)庫時,住院或門診病人對象在中間層被集成至一個單獨(dú)的實(shí)體中。對象—關(guān)系映射需要在某點(diǎn)發(fā)生,通常是在中間層。但是在一些情況下,開發(fā)人員會使用像Hibernate這樣的數(shù)據(jù)庫抽取層,它在介于中間層邏輯和數(shù)據(jù)庫本身的數(shù)據(jù)庫接口層進(jìn)行對象—關(guān)系映射。該層中的對象—關(guān)系映射操作常常很麻煩而且效率不高。上例中偽操作可能是:
(1)Get new patient id.
(2)Insert patient information.
(3)If outpatient, insert outpatient information.
(4)If inpatient, insert inpatient information.
這可能會導(dǎo)致抽取層的多次網(wǎng)絡(luò)交互。有許多抽取層(包括Hibernate)高度依賴于替代觸發(fā)器來實(shí)現(xiàn)最終的數(shù)據(jù)語義模式分解。該邏輯(從抽取層的角度)被簡化為對視圖的一個單獨(dú)插入,如下:
(1)Insert all patient information into patient view.
(2)Instead of trigger fires with following logic.
a.Get new patient id.
b.Insert patient data into patient table.
c.If outpatient, insert outpatient information.
d.If inpatient, insert inpatient information.
這不僅能加快開發(fā)速度,還能在應(yīng)用程序和數(shù)據(jù)庫模式之間提供一個常常需要的抽取層。通過該方法,對任一方的小改動都有可能無需更改對方。
5.2.2 手工數(shù)據(jù)分區(qū)
替代觸發(fā)器的另一用途就是提供了普通的統(tǒng)一接口來進(jìn)行手工表分區(qū),以便對應(yīng)用程序或最終用戶隱藏分區(qū)。考慮一個至少要將數(shù)據(jù)在線保留7年的財(cái)務(wù)應(yīng)用軟件。如果都存在一張表中,則表的大小會以極大的比例增長。常見的技術(shù)(尤其在DSS應(yīng)用程序中)是用單獨(dú)的物理表來實(shí)現(xiàn)每月或每年的數(shù)據(jù),如tran_hist_2005、tran_hist_2006、tran_hist_2007、tran_hist_2008……創(chuàng)建一個統(tǒng)一的“transaction_history”視圖用來連接單獨(dú)的表,例如:
create view transaction_history as
select * from tran _hist _2009 union all
select * from tran _hist _2008 union all
select * from tran _hist _2007 union all
select * from tran _hist _2006 union all
select * from tran _hist _2005
…
“分區(qū)”隨著時間的改變可有不同的權(quán)限。例如,去年,一個用戶插入(或更新)tran_hist_2008表中的數(shù)據(jù)。今年,可廢除大部分用戶的插入、更新和刪除權(quán)限,防止意外數(shù)據(jù)修改。ASE中的語義分區(qū)不支持不同分區(qū)、不同權(quán)限。
“分區(qū)”可擁有不同的索引。例如,由于更有可能是OLTP或混合負(fù)載處理,最近的交易記錄與常見的查詢有不同的查詢參數(shù)。較早的“分區(qū)”可能需要不同的索引來支持更復(fù)雜的DSS類型查詢。ASE的語義分區(qū)不支持不同分區(qū)、不同索引。
“分區(qū)”可與單獨(dú)的命名緩存綁定。例如,較早的數(shù)據(jù)和索引可能會沖刷緩存中較多當(dāng)前的數(shù)據(jù)。通過使用單獨(dú)的物理表,較早的數(shù)據(jù)能與較小的命名緩存綁定,在緩存中最大程度保留當(dāng)前的數(shù)據(jù)操作。
每個“分區(qū)”本身還可以是語義分區(qū)表。例如,如果表是按年進(jìn)行物理分區(qū)的,單獨(dú)的表可根據(jù)月份來進(jìn)行語義分區(qū),進(jìn)一步改善維護(hù)時間?;蛘哒Z義分區(qū)可在不同的鍵上完成, 例如客戶/交易類型,或者甚至用另一種分區(qū)類型(哈希而非范圍)。ASE中的語義分區(qū)不支持多層級分區(qū)。
這些是額外的表分區(qū)優(yōu)勢,諸如隔離維護(hù)每個分區(qū)的行動。但是,它存在一個大問題每當(dāng)一個時間段趨近結(jié)束時,不僅需要創(chuàng)建一個新的分區(qū),而且涵蓋了分區(qū)的視圖必須更改,加入新表并移除舊表。雖然修改視圖定義并不需要花一秒鐘時間,但必須在無人使用該視圖時完成,所以必須在行動時強(qiáng)制暫停。另外,真正完整的改變需要以下內(nèi)容:
(1)創(chuàng)建新的“當(dāng)前”分區(qū)表、索引和用戶權(quán)限。
(2)更新視圖定義,刪除并重建的同時修改替代觸發(fā)器和用戶權(quán)限。
(3)去除最近的“當(dāng)前”分區(qū)的權(quán)限。
(4)從最近的“當(dāng)前”分區(qū)中支持OLTP的索引。
(5)在最近的“當(dāng)前”分區(qū)中增加支持DSS查詢的索引。
為了改變視圖定義而造成的維護(hù)和縮短服務(wù)時間要求是本方法的劣勢之一,還可能由于改變了對象ID而對預(yù)編譯對象(例如存儲過程)造成不確定的影響。另一個明確的考慮就是因?yàn)閮?yōu)化器并不知道每個分區(qū)與什么查詢語義相關(guān),結(jié)果就可能常常出現(xiàn)對所有數(shù)據(jù)的訪問,頻繁創(chuàng)建包含任意謂詞結(jié)果的工作表,并將工作表用于查詢處理中。若是語義分區(qū),則優(yōu)化器了解分區(qū)鍵,能避免中間的工作表并能執(zhí)行分區(qū)消除。雖然表的分區(qū)是像上述那樣離散的集合,而同樣的鍵將觸發(fā)優(yōu)化器去了解沒有可用的結(jié)果,并且可縮短union all查詢的周期。
關(guān)于ASE 15,經(jīng)常被問到的問題之一是對開發(fā)人員都有哪些特性?贊成開源系統(tǒng)的人們傾向那些產(chǎn)品所吹捧的“開發(fā)人員”特性,并抱怨主流的RDBMS系統(tǒng)長時間關(guān)注DBA,已經(jīng)忽略了開發(fā)人員。那些產(chǎn)品中的一個嚴(yán)峻缺陷就是查詢優(yōu)化,查詢優(yōu)化器100%的是完全關(guān)注開發(fā)人員的特性。畢竟,日常運(yùn)營的DBA通常不會關(guān)心查詢優(yōu)化器運(yùn)行得如何,只要系統(tǒng)性能在可接受的資源消耗范圍內(nèi)。正是開發(fā)人員才去考慮該產(chǎn)品是否支持星型連接等。
如果考慮它,企業(yè)級DBMS產(chǎn)品的大部分精髓都被賦予了查詢優(yōu)化,一定程度地重寫查詢優(yōu)化器將會耗費(fèi)博士研發(fā)團(tuán)隊(duì)多年的辛勤工作。毫無疑問,在ASE 15.0中最大的改變正是它—完全重寫的查詢優(yōu)化器。
重寫優(yōu)化器需要滿足不斷增長的混合負(fù)載、OLAP和甚至是DSS應(yīng)用程序的需求,由于要滿足實(shí)時報(bào)表或普通應(yīng)用程序擴(kuò)展以利用數(shù)據(jù)保持力的改變來滿足業(yè)務(wù)需求,諸如市場、趨勢分析或其他源于歷史數(shù)據(jù)的信息,如客戶波動??紤]以下OLTP與DSS應(yīng)用程序的趨勢變遷描繪圖:
圖3 OLTP 和 DSS 應(yīng)用程序趨勢
注意OLTP與DSS系統(tǒng)的變遷,為了填補(bǔ)它們之間的空缺而產(chǎn)生了兩類新的需求—實(shí)時報(bào)表和實(shí)時分析。為了支持實(shí)時報(bào)表復(fù)雜查詢處理的變化,ASE完全重寫了查詢優(yōu)化器,增加了新的典型DSS/報(bào)表優(yōu)化特性,例如:DSS連接技術(shù),諸如合并連接(merge join)、哈希連接(hash join)、N陣嵌套循環(huán)連接(n-ary nested loop join)和對星型模型的支持;支持聚合、聯(lián)合和去重的更快算法;改進(jìn)了對并行查詢的支持,包括導(dǎo)向/矢量連接以減少資源使用。
非常有用的也是比較復(fù)雜的特性之一是優(yōu)化目標(biāo)和標(biāo)準(zhǔn)。對優(yōu)化器工程師來說,關(guān)鍵需要考慮開發(fā)出的優(yōu)化器能在最快的時間內(nèi)能找到優(yōu)化的執(zhí)行計(jì)劃,因?yàn)閮?yōu)化時間很容易超過執(zhí)行時間。例如,一個12向的連接涉及12張相對大的表(每個表在10萬至1 000萬行),需要10 min優(yōu)化但僅需30 s去執(zhí)行。因此,如果優(yōu)化器了解應(yīng)用程序的本質(zhì),它就能避免在優(yōu)化階段的前期找到一個查詢計(jì)劃后,又竭盡全力去尋找可能不會比該計(jì)劃更快的查詢計(jì)劃。ASE 15.0實(shí)施了3個特性以達(dá)此目的—優(yōu)化目標(biāo)、超時和標(biāo)準(zhǔn),見表10。
表10 不同優(yōu)化目標(biāo)和一些關(guān)鍵查詢技術(shù)之間的高層級關(guān)系
雖然allrows_dss能運(yùn)行所有內(nèi)容看起來很誘人,但是請記住前面關(guān)于優(yōu)化時間超出執(zhí)行時間的討論。一個關(guān)鍵的原因是合并與哈希連接被認(rèn)為是DSS類型的操作,因?yàn)樗鼈兗俣ㄟB接不會被索引完全覆蓋,通??赡懿⒉皇羌聪瘓?bào)表查詢的情況。因此,這樣的連接條件通常會因數(shù)據(jù)排序而受益,要么是物理地要么是內(nèi)存哈希表,與連接排序的連接列。較嚴(yán)厲的OLTP系統(tǒng)應(yīng)用索引來強(qiáng)制主外鍵。
雖然“容量規(guī)劃”常常被包含在開發(fā)周期中,而“負(fù)載管理”卻常被忽略。不幸的是,業(yè)務(wù)用戶通常讓硬件/軟件來自動執(zhí)行負(fù)載均衡,還需要考慮業(yè)務(wù)優(yōu)先權(quán),簡直就是不可能的任務(wù)。事實(shí)是不同的應(yīng)用程序常常會有不同的優(yōu)化需求,使用錯誤的技術(shù)同時支持所有的需求將造成失敗。請認(rèn)真考慮,如何去滿足沖突的需求:高速插入/最小化優(yōu)化;復(fù)雜查詢與更長時間的優(yōu)化需求。在不斷改變的現(xiàn)實(shí)中,日趨快速的 CPU,大量廉價的內(nèi)存?,F(xiàn)在更傾向于用更多的CPU和內(nèi)存來執(zhí)行密集算法么?四核=低價的大型SMP。它不僅帶來了第2階段的應(yīng)用程序整合,它增加了復(fù)雜度,還在更低的價格點(diǎn)上提供了并行策略的CPU資源。在從未如此擴(kuò)展的領(lǐng)域中,更大的數(shù)據(jù)量和更大的使用人群。
好的方法是通過會話級別和查詢相關(guān)的優(yōu)化控制,讓開發(fā)人員來控制優(yōu)化。因此,ASE 15不僅增加了DSS優(yōu)化技術(shù),它還令其可配置并通過優(yōu)化目標(biāo)提供了3個初始的優(yōu)化情形。開發(fā)人員必須考慮應(yīng)用程序組件的本質(zhì)并與DBA一道工作,為不同的應(yīng)用程序?qū)嵤皟?yōu)化情形”,然后這些可以根據(jù)應(yīng)用程序名稱或其它特質(zhì)來通過登錄觸發(fā)器實(shí)現(xiàn)。通過這些特性,OLTP應(yīng)用程序能避免不適合OLTP的長時間優(yōu)化或復(fù)雜優(yōu)化算法,而報(bào)表應(yīng)用程序則可利用諸如索引聯(lián)合、濃密連接等的新功能。使用支持表來存儲優(yōu)化情形的登錄觸發(fā)器例子如下:
-- created in master to allow prevent login failures in case the server needs to
-- be booted with traceflag to recover master database only
use master
go
create table optimization_profile (
appnamevarchar(30) not null,
opt_goalvarchar(20) not null,
parallel _deg tinyintnot null,
use_stmtcache bit not null,
use _mergejoin bit not null,
use _hashjoin bit not null,
use _idxunion bit not null,
delayed _commitbit not null,
primary key (appname)
)
go
exec sp_logintrigger 'drop' go
if exists (select 1 from sysobjects
where name= ' sp_optimization_profile' and type='P' and uid=user_id()) drop procedure sp_optimization_profile
go
print "...creating procedure: 'sp_optimization_profile'" go
create procedure sp_optimization_profile as begin
declare @appnamevarchar(30),
@opt _goal varchar(20),
@use_stmtcachebit,
@use_mergejoinbit,
@use_hashjoinbit,
@use_idxunionbit,
@delayed_commitbit
if suser_name()='sa' return 0
if has _role('sa _role',0)=1 return 0 select @appname= (case
when clientapplname is not null then clientapplname else program_name
end)
from master.. sysprocesses
where spid=@@spid
set export on
if exists (select appname
from master. . optimization_profile where appname= @ appn ame)
begin
select @opt _goal=opt _goal,
@use_stmtcache=use_stmtcache from master. . optimization_profile
where appname= @ appname
if @opt_goal="allrows_oltp" set plan optgoal allrows_oltp if @opt_goal="allrows _mix" set plan optgoal allrows _mix if@opt_goal="allrows_dss" set plan optgoal allrows_dss
if @use_stmtcache=1
begin
set statement_cache on set literal _autoparam on
end else begin
set statement_cache off
end
if @delayed_commit=1 set delayed _commit on ...
end
return 0
end
go
grant exec on sp _optimization_profile to public go
exec sp_logintrigger 'master. .sp_optimization_profile' go
如果一個單獨(dú)的服務(wù)器試圖支持不同類型的應(yīng)用程序(OLTP和DSS),則強(qiáng)烈推薦使用該技術(shù),因其支持應(yīng)用程序開發(fā)人員控制每個應(yīng)用程序必要的優(yōu)化配置,而無需在應(yīng)用程序中進(jìn)行硬編碼配置。除了優(yōu)化情形外,開發(fā)人員也必須考慮臨時表和應(yīng)用程序相關(guān)tempdb的負(fù)載管理。當(dāng)一個服務(wù)器與DSS用戶共享時,這將改善需要支持混合負(fù)載的OLTP應(yīng)用程序響應(yīng)度。當(dāng)大型的DSS查詢充滿tempdb時,通過避免tempdb掛起問題,它也能改善OLTP應(yīng)用程序的可用性。