sql語句優化之SQL Server(具體整頓)。本站提示廣大學習愛好者:(sql語句優化之SQL Server(具體整頓))文章只能為提供參考,不一定能成為您想要的結果。以下是sql語句優化之SQL Server(具體整頓)正文
MS SQL Server查詢優化辦法
查詢速度慢的緣由許多,罕見以下幾種
1、沒有索引或許沒有效到索引(這是查詢慢最多見的成績,是法式設計的缺點)
2、I/O吞吐量小,構成了瓶頸效應。
3、沒有創立盤算列招致查詢不優化。
4、內存缺乏
5、收集速度慢
6、查詢出的數據量過年夜(可以采取屢次查詢,其他的辦法下降數據量)
7、鎖或許逝世鎖(這也是查詢慢最多見的成績,是法式設計的缺點)
8、sp_lock,sp_who,運動的用戶檢查,緣由是讀寫競爭資本。
9、前往了不用要的行和列
10、查詢語句欠好,沒有優化
可以經由過程以下辦法來優化查詢
1、把數據、日記、索引放到分歧的I/O裝備上,增長讀取速度,之前可以將Tempdb應放在RAID0上,SQL2000不在支撐。數據量(尺寸)越年夜,進步I/O越主要.
2、縱向、橫向朋分表,削減表的尺寸(sp_spaceuse)
3、進級硬件
4、依據查詢前提,樹立索引,優化索引、優化拜訪方法,限制成果集的數據量。留意填充因子要恰當(最好是應用默許值0)。索引應當盡可能小,應用字節數小的列建索引好(參照索引的創立),不要對無限的幾個值的字段建單一索引如性別字段
5、進步網速;
6、擴展辦事器的內存,Windows 2000和SQL server 2000能支撐4-8G的內存。設置裝備擺設虛擬內存:虛擬內存年夜小應基於盤算機上並發運轉的辦事停止設置裝備擺設。運轉 Microsoft SQL Server? 2000 時,可斟酌將虛擬內存年夜小設置為盤算機中裝置的物理內存的 1.5 倍。假如別的裝置了全文檢索功效,並盤算運轉 Microsoft 搜刮辦事以便履行全文索引和查詢,可斟酌:將虛擬內存年夜小設置裝備擺設為至多是盤算機中裝置的物理內存的 3 倍。將 SQL Server max server memory 辦事器設置裝備擺設選項設置裝備擺設為物理內存的 1.5 倍(虛擬內存年夜小設置的一半)。
7、增長辦事器CPU個數;然則必需明確並行處置串行處置更須要資本例如內存。應用並行照樣串行程是MsSQL主動評價選擇的。單個義務分化成多個義務,便可以在處置器上運轉。例如耽誤查詢的排序、銜接、掃描和GROUP BY字句同時履行,SQL SERVER依據體系的負載情形決議最優的並行品級,龐雜的須要消費年夜量的CPU的查詢最合適並行處置。然則更新操作UPDATE,INSERT, DELETE還不克不及並行處置。
8、假如是應用like停止查詢的話,簡略的應用index是不可的,然則全文索引,耗空間。 like 'a%' 應用索引 like '%a' 不應用索援用 like '%a%' 查詢時,查詢耗時和字段值總長度成反比,所以不克不及用CHAR類型,而是VARCHAR。關於字段的值很長的建全文索引。
9、DB Server 和APPLication Server 分別;OLTP和OLAP分別
10、散布式分區視圖可用於完成數據庫辦事器結合體。結合體是一組離開治理的辦事器,但它們互相協作分管體系的處置負荷。這類經由過程分區數據構成數據庫辦事器結合體的機制可以或許擴展一組辦事器,以支撐年夜型的多層 Web 站點的處置須要。有關更多信息,拜見設計結合數據庫辦事器。(參照SQL贊助文件'分區視圖')
a、在完成分區視圖之前,必需先程度分區表
b、在創立成員表後,在每一個成員辦事器上界說一個散布式分區視圖,而且每一個視圖具有雷同的稱號。如許,援用散布式分區視圖名的查詢可以在任何一個成員辦事器上運轉。體系操作好像每一個成員辦事器上都有一個原始表的復本一樣,但其實每一個辦事器上只要一個成員表和一個散布式分區視圖。數據的地位對運用法式是通明的。
11、重建索引 DBCC REINDEX ,DBCC INDEXDEFRAG,壓縮數據和日記 DBCC SHRINKDB,DBCC SHRINKFILE. 設置主動壓縮日記.關於年夜的數據庫不要設置數據庫主動增加,它會下降辦事器的機能。 在T-sql的寫法上有很年夜的講求,上面列出罕見的要點:起首,DBMS處置查詢籌劃的進程是如許的:
1、 查詢語句的詞法、語法檢討
2、 將語句提交給DBMS的查詢優化器
3、 優化器做代數優化和存取途徑的優化
4、 由預編譯模塊生成查詢計劃
5、 然後在適合的時光提交給體系處置履行
6、 最初將履行成果前往給用戶其次,看一下SQL SERVER的數據寄存的構造:一個頁面的年夜小為8K(8060)字節,8個頁面為一個盤區,依照B樹寄存。
12、Commit和rollback的差別 Rollback:回滾一切的事物。 Commit:提交以後的事物. 沒有需要在靜態SQL裡寫事物,假如要寫請寫在裡面如: begin tran exec(@s) commit trans 或許將靜態SQL 寫成函數或許存儲進程。
13、在查詢Select語句頂用Where字句限制前往的行數,防止表掃描,假如前往不用要的數據,糟蹋了辦事器的I/O資本,減輕了收集的累贅下降機能。假如表很年夜,在表掃描的時代將表鎖住,制止其他的聯接拜訪表,效果嚴重。
14、SQL的正文聲名對履行沒有任何影響
15、盡量不應用光標,它占用年夜量的資本。假如須要row-by-row地履行,盡可能采取非光標技巧,如:在客戶端輪回,用暫時表,Table變量,用子查詢,用Case語句等等。游標可以依照它所支撐的提取選項停止分類: 只進 必需依照從第一行到最初一行的次序提取行。FETCH NEXT 是獨一許可的提取操作,也是默許方法。可轉動性 可以在游標中任何處所隨機提取隨意率性行。游標的技巧在SQL2000下變得功效很壯大,他的目標是支撐輪回。
有四個並發選項
READ_ONLY:不許可經由過程游標定位更新(Update),且在構成成果集的行中沒有鎖。
OPTIMISTIC WITH valueS:悲觀並發掌握是事務掌握實際的一個尺度部門。悲觀並發掌握用於如許的情況,即在翻開游標及更新行的距離中,只要很小的機遇讓第二個用戶更新某一行。當某個游標以此選項翻開時,沒有鎖掌握個中的行,這將有助於最年夜化其處置才能。假如用戶試圖修正某一行,則此行確當前值會與最初一次提取此行時獲得的值停止比擬。假如任何值產生轉變,則辦事器就會曉得其別人已更新了此行,並會前往一個毛病。假如值是一樣的,辦事器就履行修正。 選擇這個並發選項OPTIMISTIC WITH ROW VERSIONING:此悲觀並發掌握選項基於行版本掌握。應用行版本掌握,個中的表必需具有某種版本標識符,辦事器可用它來肯定該行在讀入游標後能否有所更改。
在 SQL Server 中,這特性能由 timestamp 數據類型供給,它是一個二進制數字,表現數據庫中更改的絕對次序。每一個數據庫都有一個全局以後時光戳值:@@DBTS。每次以任何方法更改帶有 timestamp 列的行時,SQL Server 先在時光戳列中存儲以後的 @@DBTS 值,然後增長 @@DBTS 的值。假如某 個表具有 timestamp 列,則時光戳會被記到行級。辦事器便可以比擬某行確當前時光戳值和前次提取時所存儲的時光戳值,從而肯定該行能否已更新。辦事器不用比擬一切列的值,只需比擬 timestamp 列便可。假如運用法式對沒有 timestamp 列的表請求基於行版本掌握的悲觀並發,則游標默許為基於數值的悲觀並發掌握。
SCROLL LOCKS 這個選項完成消極並發掌握。在消極並發掌握中,在把數據庫的行讀入游標成果集時,運用法式將試圖鎖定命據庫行。在應用辦事器游標時,將行讀入游標時會在其上放置一個更新鎖。假如在事務內翻開游標,則該事務更新鎖將一向堅持到事務被提交或回滾;當提取下一行時,將除去游標鎖。假如在事務外翻開游標,則提取下一行時,鎖就被拋棄。是以,每當用戶須要完整的消極並發掌握時,游標都應在事務內翻開。更新鎖將阻攔任何其它義務獲得更新鎖或排它鎖,從而阻攔其它義務更新該行。
但是,更新鎖其實不阻攔同享鎖,所以它不會阻攔其它義務讀取行,除非第二個義務也在請求帶更新鎖的讀取。轉動鎖依據在游標界說的 SELECT 語句中指定的鎖提醒,這些游標並發選項可以生成轉動鎖。轉動鎖在提取時在每行上獲得,並堅持到下次提取或許游標封閉,以先產生者為准。下次提取時,辦事器為新提取中的行獲得轉動鎖,並釋放前次提取中行的轉動鎖。轉動鎖自力於事務鎖,並可以堅持到一個提交或回滾操作以後。假如提交時封閉游標的選項為關,則 COMMIT 語句其實不封閉任何翻開的游標,並且轉動鎖被保存到提交以後,以保護對所提取數據的隔離。所獲得轉動鎖的類型取決於游標並發選項和游標 SELECT 語句中的鎖提醒。
鎖提醒 只讀 悲觀數值 悲觀行版本掌握 鎖定無提醒 未鎖定 未鎖定 未鎖定 更新 NOLOCK 未鎖定 未鎖定 未鎖定 未鎖定 HOLDLOCK 同享 同享 同享 更新 UPDLOCK 毛病 更新 更新 更新 TABLOCKX 毛病 未鎖定 未鎖定 更新其它 未鎖定 未鎖定 未鎖定 更新 *指定 NOLOCK 提醒將使指定了該提醒的表在游標內是只讀的。
16、用Profiler來跟蹤查詢,獲得查詢所需的時光,找出SQL的成績地點;用索引優化器優化索引
17、留意UNion和UNion all 的差別。UNION all好
18、留意應用DISTINCT,在沒有需要時不要用,它同UNION一樣會使查詢變慢。反復的記載在查詢裡是沒有成績的
19、查詢時不要前往不須要的行、列
20、用sp_configure 'query governor cost limit'或許SET QUERY_GOVERNOR_COST_LIMIT來限制查詢消費的資本。當評價查詢消費的資本超越限制時,辦事器主動撤消查詢,在查詢之前就抹殺失落。 SET LOCKTIME設置鎖的時光
21、用select top 100 / 10 Percent 來限制用戶前往的行數或許SET ROWCOUNT來限制操作的行
22、在SQL2000之前,普通不要用以下的字句: "IS NULL", " <> ", "!=", "!> ", "! <", "NOT", "NOT EXISTS", "NOT IN", "NOT LIKE", and "LIKE '%500'",由於他們不走索引滿是表掃描。也不要在WHere字句中的列名加函數,如Convert,substring等,假如必需用函數的時刻,創立盤算列再創立索引來替換.還可以變通寫法:WHERE SUBSTRING(firstname,1,1) = 'm'改成WHERE firstname like 'm%'(索引掃描),必定要將函數和列名離開。而且索引不克不及建得太多和太年夜。NOT IN會屢次掃描表,應用EXISTS、NOT EXISTS ,IN , LEFT OUTER JOIN 來替換,特殊是左銜接,而Exists比IN更快,最慢的是NOT操作.假如列的值含有空,之前它的索引不起感化,如今2000的優化器可以或許處置了。雷同的是IS NULL,“NOT", "NOT EXISTS", "NOT IN"能優化她,而” <> ”等照樣不克不及優化,用不到索引。
23、應用Query Analyzer,檢查SQL語句的查詢籌劃和評價剖析能否是優化的SQL。普通的20%的代碼占領了80%的資本,我們優化的重點是這些慢的處所。
24、假如應用了IN或許OR等時發明查詢沒有走索引,應用顯示聲名指定索引: SELECT * FROM PersonMember (INDEX = IX_Title) WHERE processid IN (‘男',‘女')
25、將須要查詢的成果事後盤算好放在表中,查詢的時刻再SELECT。這在SQL7.0之前是最主要的手腕。例如病院的住院費盤算。
26、MIN() 和 MAX()能應用到適合的索引
27、數據庫有一個准繩是代碼離數據越近越好,所以優先選擇Default,順次為Rules,Triggers, Constraint(束縛如外健主健CheckUNIQUE……,數據類型的最年夜長度等等都是束縛),Procedure.如許不只保護任務小,編寫法式質量高,而且履行的速度快。
28、假如要拔出年夜的二進制值到Image列,應用存儲進程,萬萬不要用內嵌INsert來拔出(不知JAVA能否)。由於如許運用法式起首將二進制值轉換成字符串(尺寸是它的兩倍),辦事器遭到字符後又將他轉換成二進制值.存儲進程就沒有這些舉措: 辦法:Create procedure p_insert as insert into table(Fimage) values (@image), 在前台挪用這個存儲進程傳入二進制參數,如許處置速度顯著改良。
29、Between在某些時刻比IN速度更快,Between可以或許更快地依據索引找到規模。用查詢優化器可見赴任別。 select * from chineseresume where title in ('男','女') Select * from chineseresume where between '男' and '女' 是一樣的。因為in會在比擬屢次,所以有時會慢些。
30、在需要是對全局或許部分暫時表創立索引,有時可以或許進步速度,但不是必定會如許,由於索引也消耗年夜量的資本。他的創立同是現實表一樣。
31、不要建沒有感化的事物例如發生報表時,糟蹋資本。只要在需要應用事物時應用它。
32、用OR的字句可以分化成多個查詢,而且經由過程UNION 銜接多個查詢。他們的速度只同能否應用索引有關,假如查詢須要用到結合索引,用UNION all履行的效力更高.多個OR的字句沒有效到索引,改寫成UNION的情勢再試圖與索引婚配。一個症結的成績能否用到索引。
33、盡可能罕用視圖,它的效力低。對視圖操作比直接對表操作慢,可以用stored procedure來取代她。特殊的是不要用視圖嵌套,嵌套視圖增長了尋覓原始材料的難度。我們看視圖的實質:它是寄存在辦事器上的被優化好了的曾經發生了查詢計劃的SQL。對單個表檢索數據時,不要應用指向多個表的視圖,直接從表檢索或許僅僅包括這個表的視圖上讀,不然增長了不用要的開支,查詢遭到攪擾.為了加速視圖的查詢,MsSQL增長了視圖索引的功效。
34、沒有需要時不要用DISTINCT和ORDER BY,這些舉措可以改在客戶端履行。它們增長了額定的開支。這同UNION 和UNION ALL一樣的事理。 SELECT top 20 ad.companyname,comid,position,ad.referenceid,worklocation, convert(varchar(10),ad.postDate,120) as postDate1,workyear,degreedescription FROM jobcn_query.dbo.COMPANYAD_query ad where referenceID in('JCNAD00329667','JCNAD132168','JCNAD00337748','JCNAD00338345','JCNAD00333138','JCNAD00303570', 'JCNAD00303569','JCNAD00303568','JCNAD00306698','JCNAD00231935','JCNAD00231933','JCNAD00254567', 'JCNAD00254585','JCNAD00254608','JCNAD00254607','JCNAD00258524','JCNAD00332133','JCNAD00268618', 'JCNAD00279196','JCNAD00268613') order by postdate desc
35、在IN前面值的列表中,將湧現最頻仍的值放在最後面,湧現得起碼的放在最初面,削減斷定的次數
36、當用SELECT INTO時,它會鎖住體系表(sysobjects,sysindexes等等),壅塞其他的銜接的存取。創立暫時表時用顯示聲名語句,而不是 select INTO. drop table t_lxh begin tran select * into t_lxh from chineseresume where name = 'XYZ' --commit 在另外一個銜接中SELECT * from sysobjects可以看到 SELECT INTO 會鎖住體系表,Create table 也會鎖體系表(不論是暫時表照樣體系表)。所以萬萬不要在事物內應用它!!!如許的話假如是常常要用的暫時表請應用實表,或許暫時表變量。
37、普通在GROUP BY 個HAVING字句之前就可以剔除過剩的行,所以盡可能不要用它們來做剔除行的任務。他們的履行次序應當以下最優:select 的Where字句選擇一切適合的行,Group By用來分組個統計行,Having字句用來剔除過剩的分組。如許Group By 個Having的開支小,查詢快.關於年夜的數據行停止分組和Having非常消費資本。假如Group BY的目標不包含盤算,只是分組,那末用Distinct更快
38、一次更新多筆記錄比分屢次更新每次一條快,就是說批處置好
39、罕用暫時表,盡可能用成果集和Table類性的變量來取代它,Table 類型的變量比暫時表好
40、在SQL2000下,盤算字段是可以索引的,須要知足的前提以下:
a、盤算字段的表達是肯定的
b、不克不及用在TEXT,Ntext,Image數據類型
c、必需配制以下選項 ANSI_NULLS = ON, ANSI_PADDINGS = ON, …….
41、盡可能將數據的處置任務放在辦事器上,削減收集的開支,如應用存儲進程。存儲進程是編譯好、優化過、而且被組織到一個履行計劃裡、且存儲在數據庫中的 SQL語句,是掌握流說話的聚集,速度固然快。重復履行的靜態SQL,可使用暫時存儲進程,該進程(暫時表)被放在Tempdb中。之前因為SQL SERVER對龐雜的數學盤算不支撐,所以不能不將這個任務放在其他的層上而增長收集的開支。SQL2000支撐UDFs,如今支撐龐雜的數學盤算,函數的前往值不要太年夜,如許的開支很年夜。用戶自界說函數象光標一樣履行的消費年夜量的資本,假如前往年夜的成果采取存儲進程
42、不要在一句話裡再三的應用雷同的函數,糟蹋資本,將成果放在變量裡再挪用更快
43、SELECT COUNT(*)的效力教低,盡可能變通他的寫法,而EXISTS快.同時請留意差別: select count(Field of null) from Table 和 select count(Field of NOT null) from Table 的前往值是分歧的。
44、當辦事器的內存夠多時,配制線程數目 = 最年夜銜接數+5,如許能施展最年夜的效力;不然應用 配制線程數目 <最年夜銜接數啟用SQL SERVER的線程池來處理,假如照樣數目 = 最年夜銜接數+5,嚴重的傷害辦事器的機能。
45、依照必定的順序來拜訪你的表。假如你先鎖住表A,再鎖住表B,那末在一切的存儲進程中都要依照這個次序來鎖定它們。假如你(不經意的)某個存儲進程中先鎖定表B,再鎖定表A,這能夠就會招致一個逝世鎖。假如鎖定次序沒有被事後具體的設計好,逝世鎖很難被發明
46、經由過程SQL Server Performance Monitor監督響應硬件的負載 Memory: Page Faults / sec計數器假如該值偶然走高,注解其時有線程競爭內存。假如連續很高,則內存能夠是瓶頸。 Process:
1、% DPC Time 指在典范距離時代處置器用在緩延法式挪用(DPC)吸收和供給辦事的百分比。(DPC 正在運轉的為比尺度距離優先權低的距離)。 因為 DPC 是以特權形式履行的,DPC 時光的百分比為特權時光 百分比的一部門。這些時光零丁盤算而且不屬於距離盤算總數的一部 分。這個總數顯示了作為實例時光百分比的均勻忙時。
2、%Processor Time計數器 假如該參數值連續跨越95%,注解瓶頸是CPU。可以斟酌增長一個處置器或換一個更快的處置器。
3、% Privileged Time 指非閒置處置器時光用於特權形式的百分比。(特權形式是為操作體系組件和把持硬件驅動法式而設計的一種處置形式。它許可直接拜訪硬件和一切內存。另外一種形式為用戶形式,它是一種為運用法式、情況分體系和整數分體系設計的一種無限處置形式。操作體系將運用法式線程轉換成特權形式以拜訪操作體系辦事)。 特權時光的 % 包含為連續和 DPC 供給辦事的時光。特權時光比率高能夠是因為掉敗裝備發生的年夜數目的距離而惹起的。這個計數器將均勻忙時作為樣本時光的一部門顯示。
4、% User Time表現消耗CPU的數據庫操作,如排序,履行aggregate functions等。假如該值很高,可斟酌增長索引,盡可能應用簡略的表聯接,程度朋分年夜表格等辦法來下降該值。 Physical Disk: Curretn Disk Queue Length計數器該值應不跨越磁盤數的1.5~2倍。要進步機能,可增長磁盤。 SQLServer:Cache Hit Ratio計數器該值越高越好。假如連續低於80%,應斟酌增長內存。 留意該參數值是從SQL Server啟動後,就一向累加記數,所以運轉經由一段時光後,該值將不克不及反應體系以後值。
47、剖析select emp_name form employee where salary > 3000 在此語句中若salary是Float類型的,則優化器對其停止優化為Convert(float,3000),由於3000是個整數,我們應在編程時應用3000.0而不要等運轉時讓DBMS停止轉化。異樣字符和整型數據的轉換。
======================================================================================================
我們要做到不只會寫SQL,還要做到寫出機能優秀的SQL,以下為筆者進修、摘錄、並匯總部門材料與年夜家分享!
(1) 選擇最有用率的表名次序(只在基於規矩的優化器中有用):
ORACLE 的解析器依照從右到左的次序處置FROM子句中的表名,FROM子句中寫在最初的表(基本表 driving table)將被最早處置,在FROM子句中包括多個表的情形下,你必需選擇記載條數起碼的表作為基本表。假如有3個以上的表銜接查詢, 那就須要選擇穿插表(intersection table)作為基本表, 穿插表是指誰人被其他表所援用的表.
(2) WHERE子句中的銜接次序.:
ORACLE采取自下而上的次序解析WHERE子句,依據這個道理,表之間的銜接必需寫在其他WHERE前提之前, 那些可以過濾失落最年夜數目記載的前提必需寫在WHERE子句的末尾.
(3) SELECT子句中防止應用 ‘ * ‘:
ORACLE在解析的進程中, 會將'*' 順次轉換成一切的列名, 這個任務是經由過程查詢數據字典完成的, 這意味著將消耗更多的時光
(4) 削減拜訪數據庫的次數:
ORACLE在外部履行了很多任務: 解析SQL語句, 預算索引的應用率, 綁定變量 , 讀數據塊等;
(5) 在SQL*Plus , SQL*Forms和Pro*C中從新設置ARRAYSIZE參數, 可以增長每次數據庫拜訪的檢索數據量 ,建議值為200
(6) 應用DECODE函數來削減處置時光:
應用DECODE函數可以免反復掃描雷同記載或反復銜接雷同的表.
(7) 整合簡略,有關聯的數據庫拜訪:
假如你有幾個簡略的數據庫查詢語句,你可以把它們整合到一個查詢中(即便它們之間沒有關系)
(8) 刪除反復記載:
最高效的刪除反復記載辦法 ( 由於應用了ROWID)例子:
DELETE FROM EMP E WHERE E.ROWID > (SELECT MIN(X.ROWID)
FROM EMP X WHERE X.EMP_NO = E.EMP_NO);
(9) 用TRUNCATE替換DELETE:
當刪除表中的記載時,在平日情形下, 回滾段(rollback segments ) 用來寄存可以被恢復的信息. 假如你沒有COMMIT事務,ORACLE會將數據恢復到刪除之前的狀況(精確地說是恢復到履行刪除敕令之前的狀態) 而當應用TRUNCATE時, 回滾段不再寄存任何可被恢復的信息.當敕令運轉後,數據不克不及被恢復.是以很少的資本被挪用,履行時光也會很短. (譯者按: TRUNCATE只在刪除全表實用,TRUNCATE是DDL不是DML)
(10) 盡可能多應用COMMIT:
只需有能夠,在法式中盡可能多應用COMMIT, 如許法式的機能獲得進步,需求也會由於COMMIT所釋放的資本而削減:
COMMIT所釋放的資本:
a. 回滾段上用於恢單數據的信息.
b. 被法式語句取得的鎖
c. redo log buffer 中的空間
d. ORACLE為治理上述3種資本中的外部消費
(11) 用Where子句調換HAVING子句:
防止應用HAVING子句, HAVING 只會在檢索出一切記載以後才對成果集停止過濾. 這個處置須要排序,總計等操作. 假如能經由過程WHERE子句限制記載的數量,那就可以削減這方面的開支. (非oracle中)on、where、having這三個都可以加前提的子句中,on是最早履行,where次之,having最初,由於on是先把不相符前提的記載過濾後才停止統計,它便可以削減中央運算要處置的數據,按理說應當速度是最快的,where也應當比having快點的,由於它過濾數據後才停止sum,在兩個表聯接時才用on的,所以在一個表的時刻,就剩下where跟having比擬了。在這單表查詢統計的情形下,假如要過濾的前提沒有觸及到要盤算字段,那它們的成果是一樣的,只是where可使用rushmore技巧,而having就不克不及,在速度上後者要慢假如要觸及到盤算的字段,就表現在沒盤算之前,這個字段的值是不肯定的,依據上篇寫的任務流程,where的感化時光是在盤算之前就完成的,而having就是在盤算後才起感化的,所以在這類情形下,二者的成果會分歧。在多表聯接查詢時,on比where更夙興感化。體系起首依據各個表之間的聯接前提,把多個表分解一個暫時表後,再由where停止過濾,然後再盤算,盤算完後再由having停止過濾。因而可知,要想過濾前提起到准確的感化,起首要明確這個前提應當在甚麼時刻起感化,然後再決議放在那邊
(12) 削減對表的查詢:
在含有子查詢的SQL語句中,要特殊留意削減對表的查詢.例子:
SELECT TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = ( SELECT
TAB_NAME,DB_VER FROM TAB_COLUMNS WHERE VERSION = 604)
(13) 經由過程外部函數進步SQL效力.:
龐雜的SQL常常就義了履行效力. 可以或許控制下面的應用函數處理成績的辦法在現實任務中長短常成心義的
(14) 應用表的別號(Alias):
當在SQL語句中銜接多個表時, 請應用表的別號並把別號前綴於每一個Column上.如許一來,便可以削減解析的時光並削減那些由Column歧義惹起的語法毛病.
(15) 用EXISTS替換IN、用NOT EXISTS替換NOT IN:
在很多基於基本表的查詢中,為了知足一個前提,常常須要對另外一個表停止聯接.在這類情形下, 應用EXISTS(或NOT EXISTS)平日將進步查詢的效力. 在子查詢中,NOT IN子句將履行一個外部的排序和歸並. 不管在哪一種情形下,NOT IN都是最低效的 (由於它對子查詢中的表履行了一個全表遍歷). 為了不應用NOT IN ,我們可以把它改寫成外銜接(Outer Joins)或NOT EXISTS.
例子:
(高效)SELECT * FROM EMP (基本表) WHERE EMPNO > 0 AND EXISTS (SELECT ‘X' FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = ‘MELB')
(低效)SELECT * FROM EMP (基本表) WHERE EMPNO > 0 AND DEPTNO IN(SELECT DEPTNO FROM DEPT WHERE LOC = ‘MELB')
(16) 辨認'低效履行'的SQL語句:
固然今朝各類關於SQL優化的圖形化對象層見疊出,然則寫出本身的SQL對象來處理成績一直是一個最好的辦法:
SELECT EXECUTIONS , DISK_READS, BUFFER_GETS,
ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2) Hit_radio,
ROUND(DISK_READS/EXECUTIONS,2) Reads_per_run,
SQL_TEXT
FROM V$SQLAREA
WHERE EXECUTIONS>0
AND BUFFER_GETS > 0
AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8
ORDER BY 4 DESC;
(17) 用索引進步效力:
索引是表的一個概念部門,用來進步檢索數據的效力,ORACLE應用了一個龐雜的自均衡B-tree構造. 平日,經由過程索引查詢數據比全表掃描要快. 當ORACLE找出履行查詢和Update語句的最好途徑時, ORACLE優化器將應用索引. 異樣在聯絡多個表時應用索引也能夠進步效力. 另外一個應用索引的利益是,它供給了主鍵(primary key)的獨一性驗證.。那些LONG或LONG RAW數據類型, 你可以索引簡直一切的列. 平日, 在年夜型表中應用索引特殊有用. 固然,你也會發明, 在掃描小表時,應用索引異樣能進步效力. 固然應用索引能獲得查詢效力的進步,然則我們也必需留意到它的價值. 索引須要空間來存儲,也須要按期保護, 每當有記載在表中增減或索引列被修正時, 索引自己也會被修正. 這意味著每筆記錄的INSERT , DELETE , UPDATE將為此多支付4 , 5 次的磁盤I/O . 由於索引須要額定的存儲空間和處置,那些不用要的索引反而會使查詢反響時光變慢.。按期的重構索引是有需要的.:
ALTER INDEX <INDEXNAME> REBUILD <TABLESPACENAME>
18) 用EXISTS調換DISTINCT:
當提交一個包括一對多表信息(好比部分表和雇員表)的查詢時,防止在SELECT子句中應用DISTINCT. 普通可以斟酌用EXIST調換, EXISTS 使查詢更加敏捷,由於RDBMS焦點模塊將在子查詢的前提一旦知足後,連忙前往成果. 例子:
(低效):
SELECT DISTINCT DEPT_NO,DEPT_NAME FROM DEPT D , EMP E
WHERE D.DEPT_NO = E.DEPT_NO
(高效):
SELECT DEPT_NO,DEPT_NAME FROM DEPT D WHERE EXISTS ( SELECT ‘X'
FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO);
(19) sql語句用年夜寫的;由於oracle老是先解析sql語句,把小寫的字母轉換成年夜寫的再履行
(20) 在java代碼中盡可能罕用銜接符“+”銜接字符串!
(21) 防止在索引列上應用NOT 平日,
我們要防止在索引列上應用NOT, NOT會發生在和在索引列上應用函數雷同的影響. 當ORACLE”碰到”NOT,他就會停滯應用索引轉而履行全表掃描.
(22) 防止在索引列上應用盤算.
WHERE子句中,假如索引列是函數的一部門.優化器將不應用索引而應用全表掃描.
舉例:
低效:
SELECT … FROM DEPT WHERE SAL * 12 > 25000;
高效:
SELECT … FROM DEPT WHERE SAL > 25000/12;
(23) 用>=替換>
高效:
SELECT * FROM EMP WHERE DEPTNO >=4
低效:
SELECT * FROM EMP WHERE DEPTNO >3
二者的差別在於, 前者DBMS將直接跳到第一個DEPT等於4的記載爾後者將起首定位到DEPTNO=3的記載而且向前掃描到第一個DEPT年夜於3的記載.
(24) 用UNION調換OR (實用於索引列)
平日情形下, 用UNION調換WHERE子句中的OR將會起到較好的後果. 對索引列應用OR將形成全表掃描. 留意, 以上規矩只針對多個索引列有用. 假如有column沒有被索引, 查詢效力能夠會由於你沒有選擇OR而下降. 鄙人面的例子中, LOC_ID 和REGION上都建有索引.
高效:
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE LOC_ID = 10
UNION
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE REGION = “MELBOURNE”
低效:
SELECT LOC_ID , LOC_DESC , REGION
FROM LOCATION
WHERE LOC_ID = 10 OR REGION = “MELBOURNE”
假如你保持要用OR, 那就須要前往記載起碼的索引列寫在最後面.
(25) 用IN來調換OR
這是一條簡略易記的規矩,然則現實的履行後果還須磨練,在ORACLE8i下,二者的履行途徑仿佛是雷同的.
低效:
SELECT…. FROM LOCATION WHERE LOC_ID = 10 OR LOC_ID = 20 OR LOC_ID = 30
高效
SELECT… FROM LOCATION WHERE LOC_IN IN (10,20,30);
(26) 防止在索引列上應用IS NULL和IS NOT NULL
防止在索引中應用任何可認為空的列,ORACLE將沒法應用該索引.關於單列索引,假如列包括空值,索引中將不存在此記載. 關於復合索引,假如每一個列都為空,索引中異樣不存在此記載. 假如至多有一個列不為空,則記載存在於索引中.舉例: 假如獨一性索引樹立在表的A列和B列上, 而且表中存在一筆記錄的A,B值為(123,null) , ORACLE將不接收下一條具有雷同A,B值(123,null)的記載(拔出). 但是假如一切的索引列都為空,ORACLE將以為全部鍵值為空而空不等於空. 是以你可以拔出1000 條具有雷同鍵值的記載,固然它們都是空! 由於空值不存在於索引列中,所以WHERE子句中對索引列停止空值比擬將使ORACLE停用該索引.
低效: (索引掉效)
SELECT … FROM DEPARTMENT WHERE DEPT_CODE IS NOT NULL;
高效: (索引有用)
SELECT … FROM DEPARTMENT WHERE DEPT_CODE >=0;
(27) 老是應用索引的第一個列:
假如索引是樹立在多個列上, 只要在它的第一個列(leading column)被where子句援用時,優化器才會選擇應用該索引. 這也是一條簡略而主要的規矩,當僅援用索引的第二個列時,優化器應用了全表掃描而疏忽了索引
28) 用UNION-ALL 調換UNION ( 假如有能夠的話):
當SQL 語句須要UNION兩個查詢成果聚集時,這兩個成果聚集會以UNION-ALL的方法被歸並, 然後在輸入終究成果進步行排序. 假如用UNION ALL替換UNION, 如許排序就不是需要了. 效力就會是以獲得進步. 須要留意的是,UNION ALL 將反復輸入兩個成果聚集中雷同記載. 是以列位照樣要從營業需求剖析應用UNION ALL的可行性. UNION 將對成果聚集排序,這個操作會應用到SORT_AREA_SIZE這塊內存. 關於這塊內存的優化也是相當主要的. 上面的SQL可以用來查詢排序的消費量
低效:
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
UNION
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
高效:
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
UNION ALL
SELECT ACCT_NUM, BALANCE_AMT
FROM DEBIT_TRANSACTIONS
WHERE TRAN_DATE = '31-DEC-95'
(29) 用WHERE替換ORDER BY:
ORDER BY 子句只在兩種嚴厲的前提下應用索引.
ORDER BY中一切的列必需包括在雷同的索引中並堅持在索引中的分列次序.
ORDER BY中一切的列必需界說為非空.
WHERE子句應用的索引和ORDER BY子句中所應用的索引不克不及並列.
例如:
表DEPT包括以以下:
DEPT_CODE PK NOT NULL
DEPT_DESC NOT NULL
DEPT_TYPE NULL
低效: (索引不被應用)
SELECT DEPT_CODE FROM DEPT ORDER BY DEPT_TYPE
高效: (應用索引)
SELECT DEPT_CODE FROM DEPT WHERE DEPT_TYPE > 0
(30) 防止轉變索引列的類型.:
當比擬分歧數據類型的數據時, ORACLE主動對列停止簡略的類型轉換.
假定 EMPNO是一個數值類型的索引列.
SELECT … FROM EMP WHERE EMPNO = ‘123'
現實上,經由ORACLE類型轉換, 語句轉化為:
SELECT … FROM EMP WHERE EMPNO = TO_NUMBER(‘123')
榮幸的是,類型轉換沒有產生在索引列上,索引的用處沒有被轉變.
如今,假定EMP_TYPE是一個字符類型的索引列.
SELECT … FROM EMP WHERE EMP_TYPE = 123
這個語句被ORACLE轉換為:
SELECT … FROM EMP WHERETO_NUMBER(EMP_TYPE)=123
由於外部產生的類型轉換, 這個索引將不會被用到! 為了不ORACLE對你的SQL停止隱式的類型轉換, 最好把類型轉換用顯式表示出來. 留意當字符和數值比擬時, ORACLE會優先轉換數值類型到字符類型
(31) 須要小心的WHERE子句:
某些SELECT 語句中的WHERE子句不應用索引. 這裡有一些例子.
鄙人面的例子裡, (1)‘!=' 將不應用索引. 記住, 索引只能告知你甚麼存在於表中, 而不克不及告知你甚麼不存在於表中. (2) ‘||'是字符銜接函數. 就象其他函數那樣, 停用了索引. (3) ‘+'是數學函數. 就象其他數學函數那樣, 停用了索引. (4)雷同的索引列不克不及相互比擬,這將會啟用全表掃描.
(32) a. 假如檢索數據量跨越30%的表中記載數.應用索引將沒有明顯的效力進步.
b. 在特定情形下, 應用索引或許會比全表掃描慢, 但這是統一個數目級上的差別. 而平日情形下,應用索引比全表掃描要塊幾倍甚至幾千倍!
(33) 防止應用消耗資本的操作:
帶有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY的SQL語句會啟動SQL引擎
履行消耗資本的排序(SORT)功效. DISTINCT須要一次排序操作, 而其他的至多須要履行兩次排序. 平日, 帶有UNION, MINUS , INTERSECT的SQL語句都可以用其他方法重寫. 假如你的數據庫的SORT_AREA_SIZE分配得好, 應用UNION , MINUS, INTERSECT也是可以斟酌的, 究竟它們的可讀性很強
(34) 優化GROUP BY:
進步GROUP BY 語句的效力, 可以經由過程將不須要的記載在GROUP BY 之前過濾失落.上面兩個查詢前往雷同成果但第二個顯著就快了很多.
低效:
SELECT JOB , AVG(SAL) FROM EMP GROUP by JOB HAVING JOB = ‘PRESIDENT' OR JOB = ‘MANAGER'
高效:
SELECT JOB , AVG(SAL) FROM EMP WHERE JOB = ‘PRESIDENT' OR JOB = ‘MANAGER' GROUP by JOB
優化SQL查詢:若何寫出高機能SQL語句
1、 起首要弄明確甚麼叫履行籌劃?
履行籌劃是數據庫依據SQL語句和相干表的統計信息作出的一個查詢計劃,這個計劃是由查詢優化器主動剖析發生的,好比一條SQL語句假如用來從一個 10萬筆記錄的表中查1筆記錄,那查詢優化器會選擇“索引查找”方法,假如該表停止了歸檔,以後只剩下5000筆記錄了,那查詢優化器就會轉變計劃,采取 “全表掃描”方法。
可見,履行籌劃其實不是固定的,它是“特性化的”。發生一個准確的“履行籌劃”有兩點很主要:
(1) SQL語句能否清楚地告知查詢優化器它想干甚麼?
(2) 查詢優化器獲得的數據庫統計信息能否是最新的、准確的?
2、 同一SQL語句的寫法
關於以下兩句SQL語句,法式員以為是雷同的,數據庫查詢優化器以為是分歧的。
select * from dual
select * From dual
其實就是年夜小寫分歧,查詢剖析器就以為是兩句分歧的SQL語句,必需停止兩次解析。生成2個履行籌劃。所以作為法式員,應當包管雷同的查詢語句在任何處所都分歧,多一個空格都不可!
3、 不要把SQL語句寫得太龐雜
我常常看到,從數據庫中捕獲到的一條SQL語句打印出來有2張A4紙這麼長。普通來講這麼龐雜的語句平日都是有成績的。我拿著這2頁長的SQL語句去就教原作者,成果他說時光太長,他一時也看不懂了。可想而知,連原作者都有能夠看懵懂的SQL語句,數據庫也一樣會看懵懂。
普通,將一個Select語句的成果作為子集,然後從該子集中再停止查詢,這類一層嵌套語句照樣比擬罕見的,然則依據經歷,跨越3層嵌套,查詢優化器就很輕易給失足誤的履行籌劃。由於它被繞暈了。像這類相似人工智能的器械,畢竟比人的分辯力要差些,假如人都看暈了,我可以包管數據庫也會暈的。
別的,履行籌劃是可以被重用的,越簡略的SQL語句被重用的能夠性越高。而龐雜的SQL語句只需有一個字符產生變更就必需從新解析,然後再把這一年夜堆渣滓塞在內存裡。可想而知,數據庫的效力會多麼低下。
4、 應用“暫時表”暫存中央成果
簡化SQL語句的主要辦法就是采取暫時表暫存中央成果,然則,暫時表的利益遠遠不止這些,將暫時成果暫存在暫時表,前面的查詢就在tempdb中了,這可以免法式中屢次掃描主表,也年夜年夜削減了法式履行中“同享鎖”壅塞“更新鎖”,削減了壅塞,進步了並發機能。
5、 OLTP體系SQL語句必需采取綁定變量
select * from orderheader where changetime > '2010-10-20 00:00:01'
select * from orderheader where changetime > '2010-09-22 00:00:01'
以上兩句語句,查詢優化器以為是分歧的SQL語句,須要解析兩次。假如采取綁定變量
select * from orderheader where changetime > @chgtime @chgtime變量可以傳入任何值,如許年夜量的相似查詢可以重用該履行籌劃了,這可以年夜年夜下降數據庫解析SQL語句的累贅。一次解析,屢次重用,是進步數據庫效力的准繩。
6、 綁定變量窺伺
事物都存在兩面性,綁定變量對年夜多半OLTP處置是實用的,然則也有破例。好比在where前提中的字段是“傾斜字段”的時刻。
“傾斜字段”指該列中的絕年夜多半的值都是雷同的,好比一張生齒查詢拜訪表,個中“平易近族”這列,90%以上都是漢族。那末假如一個SQL語句要查詢30歲的漢族生齒有若干,那“平易近族”這列必定要被放在where前提中。這個時刻假如采取綁定變量@nation會存在很年夜成績。
試想假如@nation傳入的第一個值是“漢族”,那全部履行籌劃必定會選擇表掃描。然後,第二個值傳入的是“布依族”,按理說“布依族”占的比例能夠只要萬分之一,應當采取索引查找。然則,因為重用了第一次解析的“漢族”的誰人履行籌劃,那末第二次也將采取表掃描方法。這個成績就是有名的“綁定變量窺伺”,建議關於“傾斜字段”不要采取綁定變量。
7、 只在需要的情形下才應用begin tran
SQL Server中一句SQL語句默許就是一個事務,在該語句履行完成後也是默許commit的。其實,這就是begin tran的一個最小化的情勢,比如在每句語句開首隱含了一個begin tran,停止時隱含了一個commit。
有些情形下,我們須要顯式聲明begin tran,好比做“插、刪、改”操作須要同時修正幾個表,請求要末幾個表都修正勝利,要末都不勝利。begin tran 可以起到如許的感化,它可以把若干SQL語句套在一路履行,最初再一路commit。利益是包管了數據的分歧性,但任何工作都不是完善無缺的。Begin tran支付的價值是在提交之前,一切SQL語句鎖住的資本都不克不及釋放,直到commit失落。
可見,假如Begin tran套住的SQL語句太多,那數據庫的機能就蹩腳了。在該年夜事務提交之前,必定會壅塞其余語句,形成block許多。
Begin tran應用的准繩是,在包管數據分歧性的條件下,begin tran 套住的SQL語句越少越好!有些情形下可以采取觸發器同步數據,紛歧定要用begin tran。
8、 一些SQL查詢語句應加上nolock
在SQL語句中加nolock是進步SQL Server並發機能的主要手腕,在oracle中其實不須要如許做,由於oracle的構造更加公道,有undo表空間保留“數據前影”,該數據假如在修正中還未commit,那末你讀到的是它修正之前的正本,該正本放在undo表空間中。如許,oracle的讀、寫可以做到互不影響,這也是oracle 廣受誇獎的處所。SQL Server 的讀、寫是會互相壅塞的,為了進步並發機能,關於一些查詢,可以加上nolock,如許讀的時刻可以許可寫,但缺陷是能夠讀到未提交的髒數據。應用 nolock有3條准繩。
(1)查詢的成果用於“插、刪、改”的不克不及加nolock !
(2)查詢的表屬於頻仍產生頁決裂的,慎用nolock !
(3)應用暫時表一樣可以保留“數據前影”,起到相似oracle的undo表空間的功效,
能采取暫時表進步並發機能的,不要用nolock 。
9、 集合索引沒有建在表的次序字段上,該表輕易產生頁決裂
好比定單表,有定單編號orderid,也有客戶編號contactid,那末集合索引應當加在哪一個字段上呢?關於該表,定單編號是次序添加的,假如在orderid上加集合索引,新增的行都是添加在末尾,如許不輕易常常發生頁決裂。但是,因為年夜多半查詢都是依據客戶編號來查的,是以,將集合索引加在contactid上才成心義。而contactid關於定單表而言,並不是次序字段。
好比“張三”的“contactid”是001,那末“張三”的定單信息必需都放在這張表的第一個數據頁上,假如明天“張三”新下了一個定單,那該定單信息不克不及放在表的最初一頁,而是第一頁!假如第一頁放滿了呢?很負疚,該表一切數據都要往後挪動為這筆記錄騰處所。
SQL Server的索引和Oracle的索引是分歧的,SQL Server的集合索引現實上是對表依照集合索引字段的次序停止了排序,相當於oracle的索引組織表。SQL Server的集合索引就是表自己的一種組織情勢,所以它的效力長短常高的。也正由於此,拔出一筆記錄,它的地位不是隨意放的,而是要依照次序放在該放的數據頁,假如誰人數據頁沒有空間了,就惹起了頁決裂。所以很明顯,集合索引沒有建在表的次序字段上,該表輕易產生頁決裂。
已經碰著過一個情形,一名哥們的某張表重建索引後,拔出的效力年夜幅降低了。估量情形年夜概是如許的。該表的集合索引能夠沒有建在表的次序字段上,該表常常被歸檔,所以該表的數據是以一種稀少狀況存在的。好比張三下過20張定單,而比來3個月的定單只要5張,歸檔戰略是保存3個月數據,那末張三曩昔的 15張定單曾經被歸檔,留下15個空位,可以在insert產生時從新被應用。在這類情形下因為有空位可以應用,就不會產生頁決裂。然則查詢機能會比擬低,由於查詢時必需掃描那些沒稀有據的空位。
重建集合索引後情形轉變了,由於重建集合索引就是把表中的數據從新分列一遍,本來的空位沒有了,而頁的填充率又很高,拔出數據常常要產生頁決裂,所以機能年夜幅降低。
關於集合索引沒有建在次序字段上的表,能否要授與比擬低的頁填充率?能否要防止重建集合索引?是一個值得斟酌的成績!
10、加nolock後查詢常常產生頁決裂的表,輕易發生跳讀或反復讀
加nolock後可以在“插、刪、改”的同時停止查詢,然則因為同時產生“插、刪、改”,在某些情形下,一旦該數據頁滿了,那末頁決裂弗成防止,而此時nolock的查詢正在產生,好比在第100頁曾經讀過的記載,能夠會由於頁決裂而分到第101頁,這有能夠使得nolock查詢在讀101頁時反復讀到該條數據,發生“反復讀”。同理,假如在100頁上的數據還沒被讀到就分到99頁去了,那nolock查詢有能夠會漏過該記載,發生“跳讀”。
下面提到的哥們,在加了nolock後一些操作湧現報錯,估量有能夠由於nolock查詢發生了反復讀,2條雷同的記載去拔出其余表,固然會產生主鍵抵觸。
11、應用like停止隱約查詢時應留意
有的時刻會須要停止一些隱約查詢好比
select * from contact where username like ‘%yue%'
症結詞%yue%,因為yue後面用到了“%”,是以該查詢必定走全表掃描,除非需要,不然不要在症結詞前加%,
12、數據類型的隱式轉換對查詢效力的影響
sql server2000的數據庫,我們的法式在提交sql語句的時刻,沒有應用強類型提交這個字段的值,由sql server 2000主動轉換數據類型,會招致傳入的參數與主鍵字段類型紛歧致,這個時刻sql server 2000能夠就會應用全表掃描。Sql2005上沒有發明這類成績,然則照樣應當留意一下。
13、SQL Server 表銜接的三種方法
(1) Merge Join
(2) Nested Loop Join
(3) Hash Join
SQL Server 2000只要一種join方法——Nested Loop Join,假如A成果集較小,那就默許作為表面,A中每筆記錄都要去B中掃描一遍,現實掃過的行數相當於A成果集行數x B成果集行數。所以假如兩個成果集都很年夜,那Join的成果很蹩腳。
SQL Server 2005新增了Merge Join,假如A表和B表的銜接字段正好是集合索引地點字段,那末表的次序曾經排好,只需雙方拼上去就好了,這類join的開支相當於A表的成果集行數加上B表的成果集行數,一個是加,一個是乘,可見merge join 的後果要比Nested Loop Join很多多少了。
假如銜接的字段上沒有索引,那SQL2000的效力是相當低的,而SQL2005供給了Hash join,相當於暫時給A,B表的成果集加上索引,是以SQL2005的效力比SQL2000有很年夜進步,我以為,這是一個主要的緣由。
總結一下,在表銜接時要留意以下幾點:
(1) 銜接字段盡可能選擇集合索引地點的字段
(2) 細心斟酌where前提,盡可能減小A、B表的成果集
(3) 假如許多join的銜接字段都缺乏索引,而你還在用SQL Server 2000,趕忙進級吧。