欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
SQL SERVER海量數據庫的查詢(xún)優(yōu)化及分頁(yè)算法方案
很多人不知道SQL語(yǔ)句在SQL SERVER中是如何執行的,他們擔心自己所寫(xiě)的SQL語(yǔ)句會(huì )被SQL SERVER誤解。比如:
select * from table1 where name=‘zhangsan‘ and tID > 10000
  和執行:
select * from table1 where tID > 10000 and name=‘zhangsan‘
  一些人不知道以上兩條語(yǔ)句的執行效率是否一樣,因為如果簡(jiǎn)單的從語(yǔ)句先后上看,這兩個(gè)語(yǔ)句的確是不一樣,如果tID是一個(gè)聚合索引,那么后一句僅僅從表的10000條以后的記錄中查找就行了;而前一句則要先從全表中查找看有幾個(gè)name=‘zhangsan‘的,而后再根據限制條件條件tID>10000來(lái)提出查詢(xún)結果。
  事實(shí)上,這樣的擔心是不必要的。SQL SERVER中有一個(gè)“查詢(xún)分析優(yōu)化器”,它可以計算出where子句中的搜索條件并確定哪個(gè)索引能縮小表掃描的搜索空間,也就是說(shuō),它能實(shí)現自動(dòng)優(yōu)化。
  雖然查詢(xún)優(yōu)化器可以根據where子句自動(dòng)的進(jìn)行查詢(xún)優(yōu)化,但大家仍然有必要了解一下“查詢(xún)優(yōu)化器”的工作原理,如非這樣,有時(shí)查詢(xún)優(yōu)化器就會(huì )不按照您的本意進(jìn)行快速查詢(xún)。
  在查詢(xún)分析階段,查詢(xún)優(yōu)化器查看查詢(xún)的每個(gè)階段并決定限制需要掃描的數據量是否有用。如果一個(gè)階段可以被用作一個(gè)掃描參數(SARG),那么就稱(chēng)之為可優(yōu)化的,并且可以利用索引快速獲得所需數據。
  SARG的定義:用于限制搜索的一個(gè)操作,因為它通常是指一個(gè)特定的匹配,一個(gè)值得范圍內的匹配或者兩個(gè)以上條件的AND連接。形式如下:
列名 操作符 <常數 或 變量>

<常數 或 變量> 操作符列名
  列名可以出現在操作符的一邊,而常數或變量出現在操作符的另一邊。如:
Name=’張三’
價(jià)格>5000
5000<價(jià)格
Name=’張三’ and 價(jià)格>5000
  如果一個(gè)表達式不能滿(mǎn)足SARG的形式,那它就無(wú)法限制搜索的范圍了,也就是SQL SERVER必須對每一行都判斷它是否滿(mǎn)足WHERE子句中的所有條件。所以一個(gè)索引對于不滿(mǎn)足SARG形式的表達式來(lái)說(shuō)是無(wú)用的。
  介紹完SARG后,我們來(lái)總結一下使用SARG以及在實(shí)踐中遇到的和某些資料上結論不同的經(jīng)驗:

  1、Like語(yǔ)句是否屬于SARG取決于所使用的通配符的類(lèi)型

  如:name like ‘張%’ ,這就屬于SARG

  而:name like ‘%張’ ,就不屬于SARG。

  原因是通配符%在字符串的開(kāi)通使得索引無(wú)法使用。

  2、or 會(huì )引起全表掃描

Name=’張三’ and 價(jià)格>5000 符號SARG,而:Name=’張三’ or 價(jià)格>5000 則不符合SARG。使用or會(huì )引起全表掃描。

  3、非操作符、函數引起的不滿(mǎn)足SARG形式的語(yǔ)句

  不滿(mǎn)足SARG形式的語(yǔ)句最典型的情況就是包括非操作符的語(yǔ)句,如:NOT、!=、<>、!<、!>、NOT EXISTS、NOT IN、NOT LIKE等,另外還有函數。下面就是幾個(gè)不滿(mǎn)足SARG形式的例子:

ABS(價(jià)格)<5000

Name like ‘%三’

  有些表達式,如:

WHERE 價(jià)格*2>5000

  SQL SERVER也會(huì )認為是SARG,SQL SERVER會(huì )將此式轉化為:

WHERE 價(jià)格>2500/2

  但我們不推薦這樣使用,因為有時(shí)SQL SERVER不能保證這種轉化與原始表達式是完全等價(jià)的。

  4、IN 的作用相當與OR

  語(yǔ)句:

Select * from table1 where tid in (2,3)

  和

Select * from table1 where tid=2 or tid=3

  是一樣的,都會(huì )引起全表掃描,如果tid上有索引,其索引也會(huì )失效。

  5、盡量少用NOT

  6、exists 和 in 的執行效率是一樣的

  很多資料上都顯示說(shuō),exists要比in的執行效率要高,同時(shí)應盡可能的用not exists來(lái)代替not in。但事實(shí)上,我試驗了一下,發(fā)現二者無(wú)論是前面帶不帶not,二者之間的執行效率都是一樣的。因為涉及子查詢(xún),我們試驗這次用SQL SERVER自帶的pubs數據庫。運行前我們可以把SQL SERVER的statistics I/O狀態(tài)打開(kāi)。

  (1)select title,price from titles where title_id in (select title_id from sales where qty>30)

  該句的執行結果為:

  表 ‘sales‘。掃描計數 18,邏輯讀 56 次,物理讀 0 次,預讀 0 次。

  表 ‘titles‘。掃描計數 1,邏輯讀 2 次,物理讀 0 次,預讀 0 次。

  (2)select title,price from titles where exists (select * from sales where sales.title_id=titles.title_id and qty>30)

  第二句的執行結果為:

  表 ‘sales‘。掃描計數 18,邏輯讀 56 次,物理讀 0 次,預讀 0 次。

  表 ‘titles‘。掃描計數 1,邏輯讀 2 次,物理讀 0 次,預讀 0 次。

  我們從此可以看到用exists和用in的執行效率是一樣的。

  7、用函數charindex()和前面加通配符%的LIKE執行效率一樣

  前面,我們談到,如果在LIKE前面加上通配符%,那么將會(huì )引起全表掃描,所以其執行效率是低下的。但有的資料介紹說(shuō),用函數charindex()來(lái)代替LIKE速度會(huì )有大的提升,經(jīng)我試驗,發(fā)現這種說(shuō)明也是錯誤的:

select gid,title,fariqi,reader from tgongwen where charindex(‘刑偵支隊‘,reader)>0 and fariqi>‘2004-5-5‘

  用時(shí):7秒,另外:掃描計數 4,邏輯讀 7155 次,物理讀 0 次,預讀 0 次。

select gid,title,fariqi,reader from tgongwen where reader like ‘%‘ + ‘刑偵支隊‘ + ‘%‘ and fariqi>‘2004-5-5‘

  用時(shí):7秒,另外:掃描計數 4,邏輯讀 7155 次,物理讀 0 次,預讀 0 次。

  8、union并不絕對比or的執行效率高

  我們前面已經(jīng)談到了在where子句中使用or會(huì )引起全表掃描,一般的,我所見(jiàn)過(guò)的資料都是推薦這里用union來(lái)代替or。事實(shí)證明,這種說(shuō)法對于大部分都是適用的。

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=‘2004-9-16‘ or gid>9990000

  用時(shí):68秒。掃描計數 1,邏輯讀 404008 次,物理讀 283 次,預讀 392163 次。

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=‘2004-9-16‘ 

union

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid>9990000

  用時(shí):9秒。掃描計數 8,邏輯讀 67489 次,物理讀 216 次,預讀 7499 次。

  看來(lái),用union在通常情況下比用or的效率要高的多。

  但經(jīng)過(guò)試驗,筆者發(fā)現如果or兩邊的查詢(xún)列是一樣的話(huà),那么用union則反倒和用or的執行速度差很多,雖然這里union掃描的是索引,而or掃描的是全表。

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=‘2004-9-16‘ or fariqi=‘2004-2-5‘

  用時(shí):6423毫秒。掃描計數 2,邏輯讀 14726 次,物理讀 1 次,預讀 7176 次。

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi=‘2004-9-16‘ 

union

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where  fariqi=‘2004-2-5‘

  用時(shí):11640毫秒。掃描計數 8,邏輯讀 14806 次,物理讀 108 次,預讀 1144 次。

  9、字段提取要按照“需多少、提多少”的原則,避免“select *”

  我們來(lái)做一個(gè)試驗:

select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc

  用時(shí):4673毫秒

select top 10000 gid,fariqi,title from tgongwen order by gid desc

  用時(shí):1376毫秒

select top 10000 gid,fariqi from tgongwen order by gid desc

  用時(shí):80毫秒

  由此看來(lái),我們每少提取一個(gè)字段,數據的提取速度就會(huì )有相應的提升。提升的速度還要看您舍棄的字段的大小來(lái)判斷。

  10、count(*)不比count(字段)慢

  某些資料上說(shuō):用*會(huì )統計所有列,顯然要比一個(gè)世界的列名效率低。這種說(shuō)法其實(shí)是沒(méi)有根據的。我們來(lái)看:

select count(*) from Tgongwen

  用時(shí):1500毫秒

select count(gid) from Tgongwen 

  用時(shí):1483毫秒

select count(fariqi) from Tgongwen

  用時(shí):3140毫秒

select count(title) from Tgongwen

  用時(shí):52050毫秒

  從以上可以看出,如果用count(*)和用count(主鍵)的速度是相當的,而count(*)卻比其他任何除主鍵以外的字段匯總速度要快,而且字段越長(cháng),匯總的速度就越慢。我想,如果用count(*), SQL SERVER可能會(huì )自動(dòng)查找最小字段來(lái)匯總的。當然,如果您直接寫(xiě)count(主鍵)將會(huì )來(lái)的更直接些。

  11、order by按聚集索引列排序效率最高

  我們來(lái)看:(gid是主鍵,fariqi是聚合索引列)

select top 10000 gid,fariqi,reader,title from tgongwen

  用時(shí):196 毫秒。 掃描計數 1,邏輯讀 289 次,物理讀 1 次,預讀 1527 次。

select top 10000 gid,fariqi,reader,title from tgongwen order by gid asc

  用時(shí):4720毫秒。 掃描計數 1,邏輯讀 41956 次,物理讀 0 次,預讀 1287 次。

select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc

  用時(shí):4736毫秒。 掃描計數 1,邏輯讀 55350 次,物理讀 10 次,預讀 775 次。

select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi asc

  用時(shí):173毫秒。 掃描計數 1,邏輯讀 290 次,物理讀 0 次,預讀 0 次。

select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi desc

  用時(shí):156毫秒。 掃描計數 1,邏輯讀 289 次,物理讀 0 次,預讀 0 次。

  從以上我們可以看出,不排序的速度以及邏輯讀次數都是和“order by 聚集索引列” 的速度是相當的,但這些都比“order by 非聚集索引列”的查詢(xún)速度是快得多的。

  同時(shí),按照某個(gè)字段進(jìn)行排序的時(shí)候,無(wú)論是正序還是倒序,速度是基本相當的。

  12、高效的TOP

  事實(shí)上,在查詢(xún)和提取超大容量的數據集時(shí),影響數據庫響應時(shí)間的最大因素不是數據查找,而是物理的I/0操作。如:

select top 10 * from (

select top 10000 gid,fariqi,title from tgongwen

where neibuyonghu=‘辦公室‘

order by gid desc) as a

order by gid asc

  這條語(yǔ)句,從理論上講,整條語(yǔ)句的執行時(shí)間應該比子句的執行時(shí)間長(cháng),但事實(shí)相反。因為,子句執行后返回的是10000條記錄,而整條語(yǔ)句僅返回10條語(yǔ)句,所以影響數據庫響應時(shí)間最大的因素是物理I/O操作。而限制物理I/O操作此處的最有效方法之一就是使用TOP關(guān)鍵詞了。TOP關(guān)鍵詞是SQL SERVER中經(jīng)過(guò)系統優(yōu)化過(guò)的一個(gè)用來(lái)提取前幾條或前幾個(gè)百分比數據的詞。經(jīng)筆者在實(shí)踐中的應用,發(fā)現TOP確實(shí)很好用,效率也很高。但這個(gè)詞在另外一個(gè)大型數據庫ORACLE中卻沒(méi)有,這不能說(shuō)不是一個(gè)遺憾,雖然在ORACLE中可以用其他方法(如:rownumber)來(lái)解決。在以后的關(guān)于“實(shí)現千萬(wàn)級數據的分頁(yè)顯示存儲過(guò)程”的討論中,我們就將用到TOP這個(gè)關(guān)鍵詞。

  到此為止,我們上面討論了如何實(shí)現從大容量的數據庫中快速地查詢(xún)出您所需要的數據方法。當然,我們介紹的這些方法都是“軟”方法,在實(shí)踐中,我們還要考慮各種“硬”因素,如:網(wǎng)絡(luò )性能、服務(wù)器的性能、操作系統的性能,甚至網(wǎng)卡、交換機等。

 三、實(shí)現小數據量和海量數據的通用分頁(yè)顯示存儲過(guò)程

  建立一個(gè)web 應用,分頁(yè)瀏覽功能必不可少。這個(gè)問(wèn)題是數據庫處理中十分常見(jiàn)的問(wèn)題。經(jīng)典的數據分頁(yè)方法是:ADO 紀錄集分頁(yè)法,也就是利用ADO自帶的分頁(yè)功能(利用游標)來(lái)實(shí)現分頁(yè)。但這種分頁(yè)方法僅適用于較小數據量的情形,因為游標本身有缺點(diǎn):游標是存放在內存中,很費內存。游標一建立,就將相關(guān)的記錄鎖住,直到取消游標。游標提供了對特定集合中逐行掃描的手段,一般使用游標來(lái)逐行遍歷數據,根據取出數據條件的不同進(jìn)行不同的操作。而對于多表和大表中定義的游標(大的數據集合)循環(huán)很容易使程序進(jìn)入一個(gè)漫長(cháng)的等待甚至死機。

  更重要的是,對于非常大的數據模型而言,分頁(yè)檢索時(shí),如果按照傳統的每次都加載整個(gè)數據源的方法是非常浪費資源的?,F在流行的分頁(yè)方法一般是檢索頁(yè)面大小的塊區的數據,而非檢索所有的數據,然后單步執行當前行。

  最早較好地實(shí)現這種根據頁(yè)面大小和頁(yè)碼來(lái)提取數據的方法大概就是“俄羅斯存儲過(guò)程”。這個(gè)存儲過(guò)程用了游標,由于游標的局限性,所以這個(gè)方法并沒(méi)有得到大家的普遍認可。

  后來(lái),網(wǎng)上有人改造了此存儲過(guò)程,下面的存儲過(guò)程就是結合我們的辦公自動(dòng)化實(shí)例寫(xiě)的分頁(yè)存儲過(guò)程:

CREATE procedure pagination1

(@pagesize int,  --頁(yè)面大小,如每頁(yè)存儲20條記錄

@pageindex int   --當前頁(yè)碼

)

as

set nocount on

begin

declare @indextable table(id int identity(1,1),nid int)  --定義表變量

declare @PageLowerBound int  --定義此頁(yè)的底碼

declare @PageUpperBound int  --定義此頁(yè)的頂碼

set @PageLowerBound=(@pageindex-1)*@pagesize

set @PageUpperBound=@PageLowerBound+@pagesize

set rowcount @PageUpperBound

insert into @indextable(nid) select gid from TGongwen where fariqi >dateadd(day,-365,getdate()) order by fariqi desc

select O.gid,O.mid,O.title,O.fadanwei,O.fariqi from TGongwen O,@indextable t where O.gid=t.nid

and t.id>@PageLowerBound and t.id<=@PageUpperBound order by t.id

end

set nocount off

  以上存儲過(guò)程運用了SQL SERVER的最新技術(shù)――表變量。應該說(shuō)這個(gè)存儲過(guò)程也是一個(gè)非常優(yōu)秀的分頁(yè)存儲過(guò)程。當然,在這個(gè)過(guò)程中,您也可以把其中的表變量寫(xiě)成臨時(shí)表:CREATE TABLE #Temp。但很明顯,在SQL SERVER中,用臨時(shí)表是沒(méi)有用表變量快的。所以筆者剛開(kāi)始使用這個(gè)存儲過(guò)程時(shí),感覺(jué)非常的不錯,速度也比原來(lái)的ADO的好。但后來(lái),我又發(fā)現了比此方法更好的方法。

  筆者曾在網(wǎng)上看到了一篇小短文《從數據表中取出第n條到第m條的記錄的方法》,全文如下:

從publish 表中取出第 n 條到第 m 條的記錄: 
SELECT TOP m-n+1 * 
FROM publish 
WHERE (id NOT IN 
    (SELECT TOP n-1 id 
     FROM publish)) 

id 為publish 表的關(guān)鍵字 

  我當時(shí)看到這篇文章的時(shí)候,真的是精神為之一振,覺(jué)得思路非常得好。等到后來(lái),我在作辦公自動(dòng)化系統(ASP.NET+ C#+SQL SERVER)的時(shí)候,忽然想起了這篇文章,我想如果把這個(gè)語(yǔ)句改造一下,這就可能是一個(gè)非常好的分頁(yè)存儲過(guò)程。于是我就滿(mǎn)網(wǎng)上找這篇文章,沒(méi)想到,文章還沒(méi)找到,卻找到了一篇根據此語(yǔ)句寫(xiě)的一個(gè)分頁(yè)存儲過(guò)程,這個(gè)存儲過(guò)程也是目前較為流行的一種分頁(yè)存儲過(guò)程,我很后悔沒(méi)有爭先把這段文字改造成存儲過(guò)程:

CREATE PROCEDURE pagination2
(
 @SQL nVARCHAR(4000),    --不帶排序語(yǔ)句的SQL語(yǔ)句
 @Page int,              --頁(yè)碼
 @RecsPerPage int,       --每頁(yè)容納的記錄數
 @ID VARCHAR(255),       --需要排序的不重復的ID號
 @Sort VARCHAR(255)      --排序字段及規則
)
AS

DECLARE @Str nVARCHAR(4000)

SET @Str=‘SELECT   TOP ‘+CAST(@RecsPerPage AS VARCHAR(20))+‘ * FROM (‘+@SQL+‘) T WHERE T.‘+@ID+‘NOT IN 
(SELECT   TOP ‘+CAST((@RecsPerPage*(@Page-1)) AS VARCHAR(20))+‘ ‘+@ID+‘ FROM (‘+@SQL+‘) T9 ORDER BY ‘+@Sort+‘) ORDER BY ‘+@Sort

PRINT @Str

EXEC sp_ExecuteSql @Str
GO

  其實(shí),以上語(yǔ)句可以簡(jiǎn)化為:

SELECT TOP 頁(yè)大小 *

FROM Table1

WHERE (ID NOT IN

          (SELECT TOP 頁(yè)大小*頁(yè)數 id

         FROM 表

         ORDER BY id))

ORDER BY ID

  但這個(gè)存儲過(guò)程有一個(gè)致命的缺點(diǎn),就是它含有NOT IN字樣。雖然我可以把它改造為:

SELECT TOP 頁(yè)大小 *

FROM Table1

WHERE not exists

(select * from (select top (頁(yè)大小*頁(yè)數) * from table1 order by id) b where b.id=a.id )

order by id

  即,用not exists來(lái)代替not in,但我們前面已經(jīng)談過(guò)了,二者的執行效率實(shí)際上是沒(méi)有區別的。

  既便如此,用TOP 結合NOT IN的這個(gè)方法還是比用游標要來(lái)得快一些。

  雖然用not exists并不能挽救上個(gè)存儲過(guò)程的效率,但使用SQL SERVER中的TOP關(guān)鍵字卻是一個(gè)非常明智的選擇。因為分頁(yè)優(yōu)化的最終目的就是避免產(chǎn)生過(guò)大的記錄集,而我們在前面也已經(jīng)提到了TOP的優(yōu)勢,通過(guò)TOP 即可實(shí)現對數據量的控制。

  在分頁(yè)算法中,影響我們查詢(xún)速度的關(guān)鍵因素有兩點(diǎn):TOP和NOT IN。TOP可以提高我們的查詢(xún)速度,而NOT IN會(huì )減慢我們的查詢(xún)速度,所以要提高我們整個(gè)分頁(yè)算法的速度,就要徹底改造NOT IN,同其他方法來(lái)替代它。

  我們知道,幾乎任何字段,我們都可以通過(guò)max(字段)或min(字段)來(lái)提取某個(gè)字段中的最大或最小值,所以如果這個(gè)字段不重復,那么就可以利用這些不重復的字段的max或min作為分水嶺,使其成為分頁(yè)算法中分開(kāi)每頁(yè)的參照物。在這里,我們可以用操作符“>”或“<”號來(lái)完成這個(gè)使命,使查詢(xún)語(yǔ)句符合SARG形式。如:

Select top 10 * from table1 where id>200

  于是就有了如下分頁(yè)方案:

select top 頁(yè)大小 *

from table1 

where id>

      (select max (id) from 

      (select top ((頁(yè)碼-1)*頁(yè)大小) id from table1 order by id) as T

       )     

  order by id

  在選擇即不重復值,又容易分辨大小的列時(shí),我們通常會(huì )選擇主鍵。下表列出了筆者用有著(zhù)1000萬(wàn)數據的辦公自動(dòng)化系統中的表,在以GID(GID是主鍵,但并不是聚集索引。)為排序列、提取gid,fariqi,title字段,分別以第1、10、100、500、1000、1萬(wàn)、10萬(wàn)、25萬(wàn)、50萬(wàn)頁(yè)為例,測試以上三種分頁(yè)方案的執行速度:(單位:毫秒)

頁(yè)  碼
 方案1
 方案2
 方案3
 
1
 60
 30
 76
 
10
 46
 16
 63
 
100
 1076
 720
 130
 
500
 540
 12943
 83
 
1000
 17110
 470
 250
 
1萬(wàn)
 24796
 4500
 140
 
10萬(wàn)
 38326
 42283
 1553
 
25萬(wàn)
 28140
 128720
 2330
 
50萬(wàn)
 121686
 127846
 7168
 

  從上表中,我們可以看出,三種存儲過(guò)程在執行100頁(yè)以下的分頁(yè)命令時(shí),都是可以信任的,速度都很好。但第一種方案在執行分頁(yè)1000頁(yè)以上后,速度就降了下來(lái)。第二種方案大約是在執行分頁(yè)1萬(wàn)頁(yè)以上后速度開(kāi)始降了下來(lái)。而第三種方案卻始終沒(méi)有大的降勢,后勁仍然很足。

  在確定了第三種分頁(yè)方案后,我們可以據此寫(xiě)一個(gè)存儲過(guò)程。大家知道SQL SERVER的存儲過(guò)程是事先編譯好的SQL語(yǔ)句,它的執行效率要比通過(guò)WEB頁(yè)面傳來(lái)的SQL語(yǔ)句的執行效率要高。下面的存儲過(guò)程不僅含有分頁(yè)方案,還會(huì )根據頁(yè)面傳來(lái)的參數來(lái)確定是否進(jìn)行數據總數統計。

-- 獲取指定頁(yè)的數據

CREATE PROCEDURE pagination3

@tblName   varchar(255),       -- 表名

@strGetFields varchar(1000) = ‘*‘,  -- 需要返回的列 

@fldName varchar(255)=‘‘,      -- 排序的字段名

@PageSize   int = 10,          -- 頁(yè)尺寸

@PageIndex  int = 1,           -- 頁(yè)碼

@doCount  bit = 0,   -- 返回記錄總數, 非 0 值則返回

@OrderType bit = 0,  -- 設置排序類(lèi)型, 非 0 值則降序

@strWhere  varchar(1500) = ‘‘  -- 查詢(xún)條件 (注意: 不要加 where)

AS

declare @strSQL   varchar(5000)       -- 主語(yǔ)句

declare @strTmp   varchar(110)        -- 臨時(shí)變量

declare @strOrder varchar(400)        -- 排序類(lèi)型

 

if @doCount != 0

  begin

    if @strWhere !=‘‘

    set @strSQL = "select count(*) as Total from [" + @tblName + "] where "+@strWhere

    else

    set @strSQL = "select count(*) as Total from [" + @tblName + "]"

end  

--以上代碼的意思是如果@doCount傳遞過(guò)來(lái)的不是0,就執行總數統計。以下的所有代碼都是@doCount為0的情況

else

begin

 

if @OrderType != 0

begin

    set @strTmp = "<(select min"

set @strOrder = " order by [" + @fldName +"] desc"

--如果@OrderType不是0,就執行降序,這句很重要!

end

else

begin

    set @strTmp = ">(select max"

    set @strOrder = " order by [" + @fldName +"] asc"

end

 

if @PageIndex = 1

begin

    if @strWhere != ‘‘   

    set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "  from [" + @tblName + "] where " + @strWhere + " " + @strOrder

     else

     set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "  from ["+ @tblName + "] "+ @strOrder

--如果是第一頁(yè)就執行以上代碼,這樣會(huì )加快執行速度

end

else

begin

--以下代碼賦予了@strSQL以真正執行的SQL代碼

set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "  from ["

    + @tblName + "] where [" + @fldName + "]" + @strTmp + "(["+ @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["+ @fldName + "] from [" + @tblName + "]" + @strOrder + ") as tblTmp)"+ @strOrder

 

if @strWhere != ‘‘

    set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "  from ["

        + @tblName + "] where [" + @fldName + "]" + @strTmp + "(["

        + @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["

        + @fldName + "] from [" + @tblName + "] where " + @strWhere + " "

        + @strOrder + ") as tblTmp) and " + @strWhere + " " + @strOrder

end 

end   

exec (@strSQL)

GO

  上面的這個(gè)存儲過(guò)程是一個(gè)通用的存儲過(guò)程,其注釋已寫(xiě)在其中了。

  在大數據量的情況下,特別是在查詢(xún)最后幾頁(yè)的時(shí)候,查詢(xún)時(shí)間一般不會(huì )超過(guò)9秒;而用其他存儲過(guò)程,在實(shí)踐中就會(huì )導致超時(shí),所以這個(gè)存儲過(guò)程非常適用于大容量數據庫的查詢(xún)。

  筆者希望能夠通過(guò)對以上存儲過(guò)程的解析,能給大家帶來(lái)一定的啟示,并給工作帶來(lái)一定的效率提升,同時(shí)希望同行提出更優(yōu)秀的實(shí)時(shí)數據分頁(yè)算法。

四、聚集索引的重要性和如何選擇聚集索引

  在上一節的標題中,筆者寫(xiě)的是:實(shí)現小數據量和海量數據的通用分頁(yè)顯示存儲過(guò)程。這是因為在將本存儲過(guò)程應用于“辦公自動(dòng)化”系統的實(shí)踐中時(shí),筆者發(fā)現這第三種存儲過(guò)程在小數據量的情況下,有如下現象:

  1、分頁(yè)速度一般維持在1秒和3秒之間。

  2、在查詢(xún)最后一頁(yè)時(shí),速度一般為5秒至8秒,哪怕分頁(yè)總數只有3頁(yè)或30萬(wàn)頁(yè)。

  雖然在超大容量情況下,這個(gè)分頁(yè)的實(shí)現過(guò)程是很快的,但在分前幾頁(yè)時(shí),這個(gè)1-3秒的速度比起第一種甚至沒(méi)有經(jīng)過(guò)優(yōu)化的分頁(yè)方法速度還要慢,借用戶(hù)的話(huà)說(shuō)就是“還沒(méi)有ACCESS數據庫速度快”,這個(gè)認識足以導致用戶(hù)放棄使用您開(kāi)發(fā)的系統。

  筆者就此分析了一下,原來(lái)產(chǎn)生這種現象的癥結是如此的簡(jiǎn)單,但又如此的重要:排序的字段不是聚集索引!

  本篇文章的題目是:“查詢(xún)優(yōu)化及分頁(yè)算法方案”。筆者只所以把“查詢(xún)優(yōu)化”和“分頁(yè)算法”這兩個(gè)聯(lián)系不是很大的論題放在一起,就是因為二者都需要一個(gè)非常重要的東西――聚集索引。

  在前面的討論中我們已經(jīng)提到了,聚集索引有兩個(gè)最大的優(yōu)勢:

  1、以最快的速度縮小查詢(xún)范圍。

  2、以最快的速度進(jìn)行字段排序。

  第1條多用在查詢(xún)優(yōu)化時(shí),而第2條多用在進(jìn)行分頁(yè)時(shí)的數據排序。

  而聚集索引在每個(gè)表內又只能建立一個(gè),這使得聚集索引顯得更加的重要。聚集索引的挑選可以說(shuō)是實(shí)現“查詢(xún)優(yōu)化”和“高效分頁(yè)”的最關(guān)鍵因素。

  但要既使聚集索引列既符合查詢(xún)列的需要,又符合排序列的需要,這通常是一個(gè)矛盾。

  筆者前面“索引”的討論中,將fariqi,即用戶(hù)發(fā)文日期作為了聚集索引的起始列,日期的精確度為“日”。這種作法的優(yōu)點(diǎn),前面已經(jīng)提到了,在進(jìn)行劃時(shí)間段的快速查詢(xún)中,比用ID主鍵列有很大的優(yōu)勢。

  但在分頁(yè)時(shí),由于這個(gè)聚集索引列存在著(zhù)重復記錄,所以無(wú)法使用max或min來(lái)最為分頁(yè)的參照物,進(jìn)而無(wú)法實(shí)現更為高效的排序。而如果將ID主鍵列作為聚集索引,那么聚集索引除了用以排序之外,沒(méi)有任何用處,實(shí)際上是浪費了聚集索引這個(gè)寶貴的資源。

   為解決這個(gè)矛盾,筆者后來(lái)又添加了一個(gè)日期列,其默認值為getdate()。用戶(hù)在寫(xiě)入記錄時(shí),這個(gè)列自動(dòng)寫(xiě)入當時(shí)的時(shí)間,時(shí)間精確到毫秒。即使這樣,為了避免可能性很小的重合,還要在此列上創(chuàng )建UNIQUE約束。將此日期列作為聚集索引列。

  有了這個(gè)時(shí)間型聚集索引列之后,用戶(hù)就既可以用這個(gè)列查找用戶(hù)在插入數據時(shí)的某個(gè)時(shí)間段的查詢(xún),又可以作為唯一列來(lái)實(shí)現max或min,成為分頁(yè)算法的參照物。

  經(jīng)過(guò)這樣的優(yōu)化,筆者發(fā)現,無(wú)論是大數據量的情況下還是小數據量的情況下,分頁(yè)速度一般都是幾十毫秒,甚至0毫秒。而用日期段縮小范圍的查詢(xún)速度比原來(lái)也沒(méi)有任何遲鈍。

  聚集索引是如此的重要和珍貴,所以筆者總結了一下,一定要將聚集索引建立在:

  1、您最頻繁使用的、用以縮小查詢(xún)范圍的字段上;

  2、您最頻繁使用的、需要排序的字段上。

  結束語(yǔ):

  本篇文章匯集了筆者近段在使用數據庫方面的心得,是在做“辦公自動(dòng)化”系統時(shí)實(shí)踐經(jīng)驗的積累。希望這篇文章不僅能夠給大家的工作帶來(lái)一定的幫助,也希望能讓大家能夠體會(huì )到分析問(wèn)題的方法;最重要的是,希望這篇文章能夠拋磚引玉,掀起大家的學(xué)習和討論的興趣,以共同促進(jìn),共同為公安科技強警事業(yè)和金盾工程做出自己最大的努力。

  最后需要說(shuō)明的是,在試驗中,我發(fā)現用戶(hù)在進(jìn)行大數據量查詢(xún)的時(shí)候,對數據庫速度影響最大的不是內存大小,而是CPU。在我的P4 2.4機器上試驗的時(shí)候,查看“資源管理器”,CPU經(jīng)常出現持續到100%的現象,而內存用量卻并沒(méi)有改變或者說(shuō)沒(méi)有大的改變。即使在我們的HP ML 350 G3服務(wù)器上試驗時(shí),CPU峰值也能達到90%,一般持續在70%左右。

  本文的試驗數據都是來(lái)自我們的HP ML 350服務(wù)器。服務(wù)器配置:雙Inter Xeon 超線(xiàn)程 CPU 2.4G,內存1G,操作系統Windows Server 2003 Enterprise Edition,數據庫SQL Server 2000 SP3。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
深入淺出理解索引結構
海量數據庫的查詢(xún)優(yōu)化及分頁(yè)算法方案
常用SQL語(yǔ)句書(shū)寫(xiě)技巧 - SQL Server - 數據庫 - 程序員之家
sql-索引的作用(超詳細)
SQLSERVER2008R2 索引建立的幾點(diǎn)建議
mssql 技術(shù) 查連接
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久