五種提高SQL性能的方法現(xiàn)場直播

字號(hào):

有時(shí), 為了讓應(yīng)用程序運(yùn)行得更快,所做的全部工作就是在這里或那里做一些很小調(diào)整。啊,但關(guān)鍵在于確定如何進(jìn)行調(diào)整!遲早您會(huì)遇到這種情況:應(yīng)用程序中的 SQL 查詢不能按照您想要的方式進(jìn)行響應(yīng)。它要么不返回?cái)?shù)據(jù),要么耗費(fèi)的時(shí)間長得出奇。
    如果它降低了報(bào)告或您的企業(yè)應(yīng)用程序的速度,用戶必須等待的時(shí)間過長,他們就會(huì)很不滿意。就像您的父母不想聽您解釋為什么在深更半夜才回來一樣,用戶也不會(huì)聽你解釋為什么查詢耗費(fèi)這么長時(shí)間。(“對(duì)不起,媽媽,我使用了太多的 LEFT JOIN。”)用戶希望應(yīng)用程序響應(yīng)迅速,他們的報(bào)告能夠在瞬間之內(nèi)返回分析數(shù)據(jù)。就我自己而言,如果在 Web 上沖浪時(shí)某個(gè)頁面要耗費(fèi)十多秒才能加載(好吧,五秒更實(shí)際一些),我也會(huì)很不耐煩。
    為了解決這些問題,重要的是找到問題的根源。那么,從哪里開始呢?根本原因通常在于數(shù)據(jù)庫設(shè)計(jì)和訪問它的查詢。在本月的專欄中,我將講述四項(xiàng)技術(shù),這些技術(shù)可用于提高基于 SQL Server? 的應(yīng)用程序的性能或改善其可伸縮性。我將仔細(xì)說明 LEFT JOIN、CROSS JOIN 的使用以及 IDENTITY 值的檢索。請(qǐng)記住,根本沒有神奇的解決方案。調(diào)整您的數(shù)據(jù)庫及其查詢需要占用時(shí)間、進(jìn)行分析,還需要大量的測試。這些技術(shù)都已被證明行之有效,但對(duì)您的應(yīng)用程序而言,可能其中一些技術(shù)比另一些技術(shù)更適用。
    本頁內(nèi)容
    從 INSERT 返回 IDENTITY
    內(nèi)嵌視圖與臨時(shí)表
    避免 LEFT JOIN 和 NULL
    靈活使用笛卡爾乘積
    拾遺補(bǔ)零
    從 INSERT 返回 IDENTITY
    我決定從遇到許多問題的內(nèi)容入手:如何在執(zhí)行 SQL INSERT 后檢索 IDENTITY 值。通常,問題不在于如何編寫檢索值的查詢,而在于在哪里以及何時(shí)進(jìn)行檢索。在 SQL Server 中,下面的語句可用于檢索由最新在活動(dòng)數(shù)據(jù)庫連接上運(yùn)行的 SQL 語句所創(chuàng)建的 IDENTITY 值:
    SELECT @@IDENTITY
    這個(gè) SQL 語句并不復(fù)雜,但需要記住的一點(diǎn)是:如果這個(gè)最新的 SQL 語句不是 INSERT,或者您針對(duì)非 INSERT SQL 的其他連接運(yùn)行了此 SQL,則不會(huì)獲得期望的值。您必須運(yùn)行下列代碼才能檢索緊跟在 INSERT SQL 之后且位于同一連接上的 IDENTITY,如下所示:
    INSERT INTO Products (ProductName) VALUES ('Chalk')
    SELECT @@IDENTITY
    在一個(gè)連接上針對(duì) Northwind 數(shù)據(jù)庫運(yùn)行這些查詢將返回一個(gè)名稱為 Chalk 的新產(chǎn)品的 IDENTITY 值。所以,在使用 ADO 的 Visual Basic? 應(yīng)用程序中,可以運(yùn)行以下語句:
    Set oRs = oCn.Execute("SET NOCOUNT ON;INSERT INTO Products _
    (ProductName) VALUES ('Chalk');SELECT @@IDENTITY")
    lProductID = oRs(0)
    此代碼告訴 SQL Server 不要返回查詢的行計(jì)數(shù),然后執(zhí)行 INSERT 語句,并返回剛剛為這個(gè)新行創(chuàng)建的 IDENTITY 值。SET NOCOUNT ON 語句表示返回的記錄集有一行和一列,其中包含了這個(gè)新的 IDENTITY 值。如果沒有此語句,則會(huì)首先返回一個(gè)空的記錄集(因?yàn)?INSERT 語句不返回任何數(shù)據(jù)),然后會(huì)返回第二個(gè)記錄集,第二個(gè)記錄集中包含 IDENTITY 值。這可能有些令人困惑,尤其是因?yàn)槟鷱膩砭蜎]有希望過 INSERT 會(huì)返回記錄集。之所以會(huì)發(fā)生此情況,是因?yàn)?SQL Server 看到了這個(gè)行計(jì)數(shù)(即一行受到影響)并將其解釋為表示一個(gè)記錄集。因此,真正的數(shù)據(jù)被推回到了第二個(gè)記錄集。當(dāng)然您可以使用 ADO 中的 NextRecordset 方法獲取此第二個(gè)記錄集,但如果總能夠首先返回該記錄集且只返回該記錄集,則會(huì)更方便,也更有效率。
    此方法雖然有效,但需要在 SQL 語句中額外添加一些代碼。獲得相同結(jié)果的另一方法是在 INSERT 之前使用 SET NOCOUNT ON 語句,并將 SELECT @@IDENTITY 語句放在表中的 FOR INSERT 觸發(fā)器中,如下面的代碼片段所示。這樣,任何進(jìn)入該表的 INSERT 語句都將自動(dòng)返回 IDENTITY 值。
    CREATE TRIGGER trProducts_Insert ON Products FOR INSERT AS
    SELECT @@IDENTITY
    GO
    觸發(fā)器只在 Products 表上發(fā)生 INSERT 時(shí)啟動(dòng),所以它總是會(huì)在成功 INSERT 之后返回一個(gè) IDENTITY。使用此技術(shù),您可以始終以相同的方式在應(yīng)用程序中檢索 IDENTITY 值。