五種提高 sql 效能的方法
發布日期: 4/1/2004 | 更新日期: 4/1/2004
johnny papa
data points archive
有時, 為了讓應用程式執行得更快,所做的全部工作就是在這裡或那裡做一些很小調整。啊,但關鍵在於確定如何進行調整!遲早您會遇到這種情況:應用程式中的 sql 查詢不能按照您想要的方式進行響應。它要麼不返回資料,要麼耗費的時間長得出奇。如果它降低了報告或您的企業應用程式的速度,使用者必須等待的時間過長,他們就會很不滿意。就像您的父母不想聽您解釋為什麼在深更半夜才回來一樣,使用者也不會聽你解釋為什麼查詢耗費這麼長時間。(「對不起,媽媽,我使用了太多的 left join。」)使用者希望應用程式響應迅速,他們的報告能夠在瞬間之內返回分析資料。就我自己而言,如果在 web 上衝浪時某個頁面要耗費十多秒才能載入(好吧,五秒更實際一些),我也會很不耐煩。
為了解決這些問題,重要的是找到問題的根源。那麼,從**開始呢?根本原因通常在於資料庫設計和訪問它的查詢。在本月的專欄中,我將講述四項技術,這些技術可用於提高基於 sql server? 的應用程式的效能或改善其可伸縮性。我將仔細說明 left join、cross join 的使用以及 identity 值的檢索。請記住,根本沒有神奇的解決方案。調整您的資料庫及其查詢需要占用時間、進行分析,還需要大量的測試。這些技術都已被證明行之有效,但對您的應用程式而言,可能其中一些技術比另一些技術更適用。
*本頁內容
從 insert 返回 identity
從 insert 返回 identity
內嵌檢視與臨時表
內嵌檢視與臨時表
避免 left join 和 null
避免 left join 和 null
靈活使用笛卡爾乘積
靈活使用笛卡爾乘積
拾遺補零
拾遺補零
從 insert 返回 identity
我決定從遇到許多問題的內容入手:如何在執行 sql insert 後檢索 identity 值。通常,問題不在於如何編寫檢索值的查詢,而在於在**以及何時進行檢索。在 sql server 中,下面的語句可用於檢索由最新在活動資料庫連線上執行的 sql 語句所建立的 identity 值:
select @@identity
這個 sql 語句並不複雜,但需要記住的一點是:如果這個最新的 sql 語句不是 insert,或者您針對非 insert sql 的其他連線執行了此 sql,則不會獲得期望的值。您必須執行下列**才能檢索緊跟在 insert sql 之後且位於同一連線上的 identity,如下所示:
insert into products (productname) values ('chalk')
select @@identity
在乙個連線上針對 northwind 資料庫執行這些查詢將返回乙個名稱為 chalk 的新產品的 identity 值。所以,在使用 ado 的 visual basic? 應用程式中,可以執行以下語句:
set ors = ocn.execute("set nocount on;insert into products _
(productname) values ('chalk');select @@identity")
lproductid = ors(0)
此**告訴 sql server 不要返回查詢的行計數,然後執行 insert 語句,並返回剛剛為這個新行建立的 identity 值。set nocount on 語句表示返回的記錄集有一行和一列,其中包含了這個新的 identity 值。如果沒有此語句,則會首先返回乙個空的記錄集(因為 insert 語句不返回任何資料),然後會返回第二個記錄集,第二個記錄集中包含 identity 值。這可能有些令人困惑,尤其是因為您從來就沒有希望過 insert 會返回記錄集。之所以會發生此情況,是因為 sql server 看到了這個行計數(即一行受到影響)並將其解釋為表示乙個記錄集。因此,真正的資料被推回到了第二個記錄集。當然您可以使用 ado 中的 nextrecordset 方法獲取此第二個記錄集,但如果總能夠首先返回該記錄集且只返回該記錄集,則會更方便,也更有效率。
此方法雖然有效,但需要在 sql 語句中額外新增一些**。獲得相同結果的另一方法是在 insert 之前使用 set nocount on 語句,並將 select @@identity 語句放在表中的 for insert 觸發器中,如下面的**片段所示。這樣,任何進入該錶的 insert 語句都將自動返回 identity 值。
create trigger trproducts_insert on products for insert as
select @@identity
go觸發器只在 products 表上發生 insert 時啟動,所以它總是會在成功 insert 之後返回乙個 identity。使用此技術,您可以始終以相同的方式在應用程式中檢索 identity 值。
返回頁首返回頁首
內嵌檢視與臨時表
某些時候,查詢需要將資料與其他一些可能只能通過執行 group by 然後執行標準查詢才能收集的資料進行聯接。例如,如果要查詢最新五個定單的有關資訊,您首先需要知道是哪些定單。這可以使用返回定單 id 的 sql 查詢來檢索。此資料就會儲存在臨時表(這是乙個常用技術)中,然後與 products 表進行聯接,以返回這些定單售出的產品數量:
create table #temp1 (orderid int not null, _
orderdate datetime not null)
insert into #temp1 (orderid, orderdate)
select top 5 o.orderid, o.orderdate
from orders o order by o.orderdate desc
select p.productname, sum(od.quantity) as productquantity
from #temp1 t
inner join [order details] od on t.orderid = od.orderid
inner join products p on od.productid = p.productid
group by p.productname
order by p.productname
drop table #temp1
這些 sql 語句會建立乙個臨時表,將資料插入該表中,將其他資料與該錶進行聯接,然後除去該臨時表。這會導致此查詢進行大量 i/o 操作,因此,可以重新編寫查詢,使用內嵌檢視取代臨時表。內嵌檢視只是乙個可以聯接到 from 子句中的查詢。所以,您不用在 tempdb 中的臨時表上耗費大量 i/o 和磁碟訪問,而可以使用內嵌檢視得到同樣的結果:
select p.productname,
sum(od.quantity) as productquantity
from (
select top 5 o.orderid, o.orderdate
from orders o
order by o.orderdate desc
) tinner join [order details] od on t.orderid = od.orderid
inner join products p on od.productid = p.productid
group by
p.productname
order by
p.productname
此查詢不僅比前面的查詢效率更高,而且長度更短。臨時表會消耗大量資源。如果只需要將資料聯接到其他查詢,則可以試試使用內嵌檢視,以節省資源。
返回頁首返回頁首
避免 left join 和 null
當然,有很多時候您需要執行 left join 和使用 null 值。但是,它們並不適用於所有情況。改變 sql 查詢的構建方式可能會產生將乙個花幾分鐘執行的報告縮短到只花幾秒鐘這樣的天壤之別的效果。有時,必須在查詢中調整資料的形態,使之適應應用程式所要求的顯示方式。雖然 table 資料型別會減少大量占用資源的情況,但在查詢中還有許多區域可以進行優化。sql 的乙個有價值的常用功能是 left join。它可以用於檢索第乙個表中的所有行、第二個表中所有匹配的行、以及第二個表中與第乙個表不匹配的所有行。例如,如果希望返回每個客戶及其定單,使用 left join 則可以顯示有定單和沒有定單的客戶。
此工具可能會被過度使用。left join 消耗的資源非常之多,因為它們包含與 null(不存在)資料匹配的資料。在某些情況下,這是不可避免的,但是代價可能非常高。left join 比 inner join 消耗資源更多,所以如果您可以重新編寫查詢以使得該查詢不使用任何 left join,則會得到非常可觀的回報(請參閱圖 1 中的圖)。
五種提高 SQL 效能的方法
有時,為了讓應用程式執行得更快,所做的全部工作就是在這裡或那裡做一些很小調整。啊,但關鍵在於確定如何進行調整!遲早您會遇到這種情況 應用程式中的 sql 查詢不能按照您想要的方式進行響應。它要麼不返回資料,要麼耗費的時間長得出奇。如果它降低了報告或您的企業應用程式的速度,使用者必須等待的時間過長,他...
五種提高 SQL 效能的方法
如有向 johnny 提出的問題和建議,請傳送電子郵件到 mmdata microsoft.johnny papa 是北卡羅來納州羅利市的 mjm 研究公司的資訊科技副總裁,他著有?professional ado 25 rds programming with asp 30?wrox,2000 並...
提高SQL效能方法
首先,索引是有序的,通過索引,可以避免排序 其次,排序操作是昂貴的,資源開銷較大,特別事需要排序的結果集較大時,更是如此。排序往往是成為一條sql中最消耗資源的處理步驟。所以,如果可以通過索引來避免排序,則可能降低資源的開銷,提高sql的執行效率。由於該問題是在生產環境,無法截圖,只能口述啦,實際也...