當前位置:首頁 » 編程語言 » sql處理量百萬以上
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

sql處理量百萬以上

發布時間: 2022-06-04 20:15:52

A. sql對100萬條數據的查詢和統計(主要是統計)效率提升

SELECT count(id)
FROM TBL_POS_SHOP s,
TBL_POS_POS p,
TBL_POS_CUSTOMER c,
TBL_POS_ORDER o,
TBL_POS_CARDINFO cd
WHERE o.POS_CATI = p.POS_CATI
and o.CUSTOMER_ID = c.ID
and o.SHOP_ID = s.ID
and o.CARDINFO_ID = cd.ID

B. sql 多表鏈接,數據量都百萬級別,如何效率優化

用好索引
用更好的查找引擎(/資料庫
做好表設計

實在不行,就用隊列查詢

C. 如何提高上百萬級記錄MySQL資料庫查詢速度

先安裝 Apache Spark,查詢資料庫的速度可以提升10倍。
在已有的 MySQL 伺服器之上使用 Apache Spark (無需將數據導出到 Spark 或者 Hadoop 平台上),這樣至少可以提升 10 倍的查詢性能。使用多個 MySQL 伺服器(復制或者 Percona XtraDB Cluster)可以讓我們在某些查詢上得到額外的性能提升。你也可以使用 Spark 的緩存功能來緩存整個 MySQL 查詢結果表。

思路很簡單:Spark 可以通過 JDBC 讀取 MySQL 上的數據,也可以執行 SQL 查詢,因此我們可以直接連接到 MySQL 並執行查詢。那麼為什麼速度會快呢?對一些需要運行很長時間的查詢(如報表或者BI),由於 Spark 是一個大規模並行系統,因此查詢會非常的快。MySQL 只能為每一個查詢分配一個 CPU 核來處理,而 Spark 可以使用所有集群節點的所有核。在下面的例子中,我們會在 Spark 中執行 MySQL 查詢,這個查詢速度比直接在 MySQL 上執行速度要快 5 到 10 倍。

另外,Spark 可以增加「集群」級別的並行機制,在使用 MySQL 復制或者 Percona XtraDB Cluster 的情況下,Spark 可以把查詢變成一組更小的查詢(有點像使用了分區表時可以在每個分區都執行一個查詢),然後在多個 Percona XtraDB Cluster 節點的多個從伺服器上並行的執行這些小查詢。最後它會使用map/rece 方式將每個節點返回的結果聚合在一起形成完整的結果。

D. sql server百萬級的數據,如何提高查詢效率

百萬級的數據對sqlserver來說並不算大,只要資料庫結構設計合理、sql指令合理,效率不會太差。
1.充分利用索引
2.盡量減少運算
3.盡量減小執行初期的數據量
4.減小循環
......

E. 我要處理百萬的數據量,用什麼資料庫比較合適!MSSQL 能夠承受多大的數據量

oracle ,db2 和sql server 都可以處理百萬的數據量
你可以根據你們公司的情況選擇合適的資料庫類型了.
oracle和db2可以在多平台下運行
sqlserver只能在Windows下運行
db2價格比較昂貴,對硬體要求也比較高
oracle對管理員的要求較高
反正很多因素了
你可以根據實際情況選擇

F. mysql 數據量超過百萬後怎麼處理

1、應盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。
2、對查詢進行優化,應盡量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。
3、應盡量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num is null
可以在num上設置默認值0,確保表中num列沒有null值,然後這樣查詢:
select id from t where num=0
4、盡量避免在 where 子句中使用 or 來連接條件,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num=10 or num=20
可以這樣查詢:
select id from t where num=10
union all
select id from t where num=20
5、下面的查詢也將導致全表掃描:(不能前置百分號)
select id from t where name like 『�1�7c%』
若要提高效率,可以考慮全文檢索。
6、in 和 not in 也要慎用,否則會導致全表掃描,如:
select id from t where num in(1,2,3)
對於連續的數值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
7、如果在 where 子句中使用參數,也會導致全表掃描。因為SQL只有在運行時才會解析局部變數,但優化程序不能將訪問計劃的選擇推遲到運行時;它必須在編譯時進行選擇。然 而,如果在編譯時建立訪問計劃,變數的值還是未知的,因而無法作為索引選擇的輸入項。如下面語句將進行全表掃描:
select id from t where num=@num
可以改為強制查詢使用索引:
select id from t with(index(索引名)) where num=@num
8、應盡量避免在 where 子句中對欄位進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where num/2=100
應改為:
select id from t where num=100*2
9、應盡量避免在where子句中對欄位進行函數操作,這將導致引擎放棄使用索引而進行全表掃描。如:
select id from t where substring(name,1,3)=』abc』–name以abc開頭的id
select id from t where datediff(day,createdate,』2005-11-30′)=0–』2005-11-30′生成的id
應改為:
select id from t where name like 『abc%』
select id from t where createdate>=』2005-11-30′ and createdate<』2005-12-1′
10、不要在 where 子句中的「=」左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。
11、在使用索引欄位作為條件時,如果該索引是復合索引,那麼必須使用到該索引中的第一個欄位作為條件時才能保證系統使用該索引,否則該索引將不會被使 用,並且應盡可能的讓欄位順序與索引順序相一致。
12、不要寫一些沒有意義的查詢,如需要生成一個空表結構:
select col1,col2 into #t from t where 1=0
這類代碼不會返回任何結果集,但是會消耗系統資源的,應改成這樣:
create table #t(…)
13、很多時候用 exists 代替 in 是一個好的選擇:
select num from a where num in(select num from b)
用下面的語句替換:
select num from a where exists(select 1 from b where num=a.num)
14、並不是所有索引對查詢都有效,SQL是根據表中數據來進行查詢優化的,當索引列有大量數據重復時,SQL查詢可能不會去利用索引,如一表中有欄位 sex,male、female幾乎各一半,那麼即使在sex上建了索引也對查詢效率起不了作用。
15、索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因為 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有 必要。
16.應盡可能的避免更新 clustered 索引數據列,因為 clustered 索引數據列的順序就是表記錄的物理存儲順序,一旦該列值改變將導致整個表記錄的順序的調整,會耗費相當大的資源。若應用系統需要頻繁更新 clustered 索引數據列,那麼需要考慮是否應將該索引建為 clustered 索引。
17、盡量使用數字型欄位,若只含數值信息的欄位盡量不要設計為字元型,這會降低查詢和連接的性能,並會增加存儲開銷。這是因為引擎在處理查詢和連接時會 逐個比較字元串中每一個字元,而對於數字型而言只需要比較一次就夠了。
18、盡可能的使用 varchar/nvarchar 代替 char/nchar ,因為首先變長欄位存儲空間小,可以節省存儲空間,其次對於查詢來說,在一個相對較小的欄位內搜索效率顯然要高些。
19、任何地方都不要使用 select * from t ,用具體的欄位列表代替「*」,不要返回用不到的任何欄位。
20、盡量使用表變數來代替臨時表。如果表變數包含大量數據,請注意索引非常有限(只有主鍵索引)。
21、避免頻繁創建和刪除臨時表,以減少系統表資源的消耗。
22、臨時表並不是不可使用,適當地使用它們可以使某些常式更有效,例如,當需要重復引用大型表或常用表中的某個數據集時。但是,對於一次性事件,最好使 用導出表。
23、在新建臨時表時,如果一次性插入數據量很大,那麼可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果數據量不大,為了緩和系統表的資源,應先create table,然後insert。
24、如果使用到了臨時表,在存儲過程的最後務必將所有的臨時表顯式刪除,先 truncate table ,然後 drop table ,這樣可以避免系統表的較長時間鎖定。
25、盡量避免使用游標,因為游標的效率較差,如果游標操作的數據超過1萬行,那麼就應該考慮改寫。
26、使用基於游標的方法或臨時表方法之前,應先尋找基於集的解決方案來解決問題,基於集的方法通常更有效。
27、與臨時表一樣,游標並不是不可使用。對小型數據集使用 FAST_FORWARD 游標通常要優於其他逐行處理方法,尤其是在必須引用幾個表才能獲得所需的數據時。在結果集中包括「合計」的常式通常要比使用游標執行的速度快。如果開發時 間允許,基於游標的方法和基於集的方法都可以嘗試一下,看哪一種方法的效果更好。
28、在所有的存儲過程和觸發器的開始處設置 SET NOCOUNT ON ,在結束時設置 SET NOCOUNT OFF 。無需在執行存儲過程和觸發器的每個語句後向客戶端發送 DONE_IN_PROC 消息。
29、盡量避免向客戶端返回大數據量,若數據量過大,應該考慮相應需求是否合理。
30、盡量避免大事務操作,提高系統並發能力。

G. SQL如何快速處理海量數據

在以下的文章中,我將以「辦公自動化」系統為例,探討如何在有著1000萬條數據的MS SQL SERVER資料庫中實現快速的數據提取和數據分頁。以下代碼說明了我們實例中資料庫的「紅頭文件」一表的部分數據結構:

CREATE TABLE [dbo].[TGongwen] ( --TGongwen是紅頭文件表名

[Gid] [int] IDENTITY (1, 1) NOT NULL ,
--本表的id號,也是主鍵

[title] [varchar] (80) COLLATE Chinese_PRC_CI_AS NULL ,
--紅頭文件的標題

[fariqi] [datetime] NULL ,
--發布日期

[neibuYonghu] [varchar] (70) COLLATE Chinese_PRC_CI_AS NULL ,
--發布用戶

[reader] [varchar] (900) COLLATE Chinese_PRC_CI_AS NULL ,

--需要瀏覽的用戶。每個用戶中間用分隔符「,」分開

) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

下面,我們來往資料庫中添加1000萬條數據:

declare @i int

set @i=1

while @i<=250000

begin

insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-2-5','通信科','通信科,辦公室,王局長,劉局長,張局長,admin,刑偵支隊,特勤支隊,交巡警支隊,經偵支隊,戶政科,治安支隊,外事科','這是最先的25萬條記錄')

set @i=@i+1

end

GO

declare @i int

set @i=1

while @i<=250000

begin

insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-9-16','辦公室','辦公室,通信科,王局長,劉局長,張局長,admin,刑偵支隊,特勤支隊,交巡警支隊,經偵支隊,戶政科,外事科','這是中間的25萬條記錄')

set @i=@i+1

end

GO

declare @h int

set @h=1

while @h<=100

begin

declare @i int

set @i=2002

while @i<=2003

begin

declare @j int

set @j=0

while @j<50

begin

declare @k int

set @k=0

while @k<50

begin

insert into Tgongwen(fariqi,neibuyonghu,reader,title) values(cast(@i as varchar(4))+'-8-15 3:'+cast(@j as varchar(2))+':'+cast(@j as varchar(2)),'通信科','辦公室,通信科,王局長,劉局長,張局長,admin,刑偵支隊,特勤支隊,交巡警支隊,經偵支隊,戶政科,外事科','這是最後的50萬條記錄')

set @k=@k+1

end

set @j=@j+1

end

set @i=@i+1

end

set @h=@h+1

end

GO

declare @i int

set @i=1

while @i<=9000000

begin

insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-5-5','通信科','通信科,辦公室,王局長,劉局長,張局長,admin,刑偵支隊,特勤支隊,交巡警支隊,經偵支隊,戶政科,治安支隊,外事科','這是最後添加的900萬條記錄')

set @i=@i+1000000

end

GO

通過以上語句,我們創建了25萬條由通信科於2004年2月5日發布的記錄,25萬條由辦公室於2004年9月6日發布的記錄,2002年和2003年各100個2500條相同日期、不同分秒的由通信科發布的記錄(共50萬條),還有由通信科於2004年5月5日發布的900萬條記錄,合計1000萬條。

一、因情制宜,建立「適當」的索引

建立「適當」的索引是實現查詢優化的首要前提。

索引(index)是除表之外另一重要的、用戶定義的存儲在物理介質上的數據結構。當根據索引碼的值搜索數據時,索引提供了對數據的快速訪問。事實上,沒有索引,資料庫也能根據SELECT語句成功地檢索到結果,但隨著表變得越來越大,使用「適當」的索引的效果就越來越明顯。注意,在這句話中,我們用了「適當」這個詞,這是因為,如果使用索引時不認真考慮其實現過程,索引既可以提高也會破壞資料庫的工作性能。

(一)深入淺出理解索引結構

實際上,您可以把索引理解為一種特殊的目錄。微軟的SQL SERVER提供了兩種索引:聚集索引(clustered index,也稱聚類索引、簇集索引)和非聚集索引(nonclustered index,也稱非聚類索引、非簇集索引)。下面,我們舉例來說明一下聚集索引和非聚集索引的區別:

其實,我們的漢語字典的正文本身就是一個聚集索引。比如,我們要查「安」字,就會很自然地翻開字典的前幾頁,因為「安」的拼音是「an」,而按照拼音排序漢字的字典是以英文字母「a」開頭並以「z」結尾的,那麼「安」字就自然地排在字典的前部。如果您翻完了所有以「a」開頭的部分仍然找不到這個字,那麼就說明您的字典中沒有這個字;同樣的,如果查「張」字,那您也會將您的字典翻到最後部分,因為「張」的拼音是「zhang」。也就是說,字典的正文部分本身就是一個目錄,您不需要再去查其他目錄來找到您需要找的內容。

我們把這種正文內容本身就是一種按照一定規則排列的目錄稱為「聚集索引」。

如果您認識某個字,您可以快速地從自動中查到這個字。但您也可能會遇到您不認識的字,不知道它的發音,這時候,您就不能按照剛才的方法找到您要查的字,而需要去根據「偏旁部首」查到您要找的字,然後根據這個字後的頁碼直接翻到某頁來找到您要找的字。但您結合「部首目錄」和「檢字表」而查到的字的排序並不是真正的正文的排序方法,比如您查「張」字,我們可以看到在查部首之後的檢字表中「張」的頁碼是672頁,檢字表中「張」的上面是「馳」字,但頁碼卻是63頁,「張」的下面是「弩」字,頁面是390頁。很顯然,這些字並不是真正的分別位於「張」字的上下方,現在您看到的連續的「馳、張、弩」三字實際上就是他們在非聚集索引中的排序,是字典正文中的字在非聚集索引中的映射。我們可以通過這種方式來找到您所需要的字,但它需要兩個過程,先找到目錄中的結果,然後再翻到您所需要的頁碼。

我們把這種目錄純粹是目錄,正文純粹是正文的排序方式稱為「非聚集索引」。

通過以上例子,我們可以理解到什麼是「聚集索引」和「非聚集索引」。

進一步引申一下,我們可以很容易的理解:每個表只能有一個聚集索引,因為目錄只能按照一種方法進行排序。

(二)何時使用聚集索引或非聚集索引

下面的表總結了何時使用聚集索引或非聚集索引(很重要)。

動作描述

使用聚集索引

使用非聚集索引

列經常被分組排序





返回某范圍內的數據



不應

一個或極少不同值

不應

不應

小數目的不同值



不應

大數目的不同值

不應



頻繁更新的列

不應



外鍵列





主鍵列





頻繁修改索引列

不應



事實上,我們可以通過前面聚集索引和非聚集索引的定義的例子來理解上表。如:返回某范圍內的數據一項。比如您的某個表有一個時間列,恰好您把聚合索引建立在了該列,這時您查詢2004年1月1日至2004年10月1日之間的全部數據時,這個速度就將是很快的,因為您的這本字典正文是按日期進行排序的,聚類索引只需要找到要檢索的所有數據中的開頭和結尾數據即可;而不像非聚集索引,必須先查到目錄中查到每一項數據對應的頁碼,然後再根據頁碼查到具體內容。

(三)結合實際,談索引使用的誤區

理論的目的是應用。雖然我們剛才列出了何時應使用聚集索引或非聚集索引,但在實踐中以上規則卻很容易被忽視或不能根據實際情況進行綜合分析。下面我們將根據在實踐中遇到的實際問題來談一下索引使用的誤區,以便於大家掌握索引建立的方法。

1、主鍵就是聚集索引

這種想法筆者認為是極端錯誤的,是對聚集索引的一種浪費。雖然SQL SERVER默認是在主鍵上建立聚集索引的。

通常,我們會在每個表中都建立一個ID列,以區分每條數據,並且這個ID列是自動增大的,步長一般為1。我們的這個辦公自動化的實例中的列Gid就是如此。此時,如果我們將這個列設為主鍵,SQL SERVER會將此列默認為聚集索引。這樣做有好處,就是可以讓您的數據在資料庫中按照ID進行物理排序,但筆者認為這樣做意義不大。

顯而易見,聚集索引的優勢是很明顯的,而每個表中只能有一個聚集索引的規則,這使得聚集索引變得更加珍貴。

從我們前面談到的聚集索引的定義我們可以看出,使用聚集索引的最大好處就是能夠根據查詢要求,迅速縮小查詢范圍,避免全表掃描。在實際應用中,因為ID號是自動生成的,我們並不知道每條記錄的ID號,所以我們很難在實踐中用ID號來進行查詢。這就使讓ID號這個主鍵作為聚集索引成為一種資源浪費。其次,讓每個ID號都不同的欄位作為聚集索引也不符合「大數目的不同值情況下不應建立聚合索引」規則;當然,這種情況只是針對用戶經常修改記錄內容,特別是索引項的時候會負作用,但對於查詢速度並沒有影響。

在辦公自動化系統中,無論是系統首頁顯示的需要用戶簽收的文件、會議還是用戶進行文件查詢等任何情況下進行數據查詢都離不開欄位的是「日期」還有用戶本身的「用戶名」。

通常,辦公自動化的首頁會顯示每個用戶尚未簽收的文件或會議。雖然我們的where語句可以僅僅限制當前用戶尚未簽收的情況,但如果您的系統已建立了很長時間,並且數據量很大,那麼,每次每個用戶打開首頁的時候都進行一次全表掃描,這樣做意義是不大的,絕大多數的用戶1個月前的文件都已經瀏覽過了,這樣做只能徒增資料庫的開銷而已。事實上,我們完全可以讓用戶打開系統首頁時,資料庫僅僅查詢這個用戶近3個月來未閱覽的文件,通過「日期」這個欄位來限製表掃描,提高查詢速度。如果您的辦公自動化系統已經建立的2年,那麼您的首頁顯示速度理論上將是原來速度8倍,甚至更快。

在這里之所以提到「理論上」三字,是因為如果您的聚集索引還是盲目地建在ID這個主鍵上時,您的查詢速度是沒有這么高的,即使您在「日期」這個欄位上建立的索引(非聚合索引)。下面我們就來看一下在1000萬條數據量的情況下各種查詢的速度表現(3個月內的數據為25萬條):

(1)僅在主鍵上建立聚集索引,並且不劃分時間段:

Select gid,fariqi,neibuyonghu,title from tgongwen

用時:128470毫秒(即:128秒)

(2)在主鍵上建立聚集索引,在fariq上建立非聚集索引:

select gid,fariqi,neibuyonghu,title from Tgongwen

where fariqi> dateadd(day,-90,getdate())

用時:53763毫秒(54秒)

(3)將聚合索引建立在日期列(fariqi)上:

select gid,fariqi,neibuyonghu,title from Tgongwen

where fariqi> dateadd(day,-90,getdate())

用時:2423毫秒(2秒)

雖然每條語句提取出來的都是25萬條數據,各種情況的差異卻是巨大的,特別是將聚集索引建立在日期列時的差異。事實上,如果您的資料庫真的有1000萬容量的話,把主鍵建立在ID列上,就像以上的第1、2種情況,在網頁上的表現就是超時,根本就無法顯示。這也是我摒棄ID列作為聚集索引的一個最重要的因素。

得出以上速度的方法是:在各個select語句前加:declare @d datetime

set @d=getdate()

並在select語句後加:

select [語句執行花費時間(毫秒)]=datediff(ms,@d,getdate())

2、只要建立索引就能顯著提高查詢速度

事實上,我們可以發現上面的例子中,第2、3條語句完全相同,且建立索引的欄位也相同;不同的僅是前者在fariqi欄位上建立的是非聚合索引,後者在此欄位上建立的是聚合索引,但查詢速度卻有著天壤之別。所以,並非是在任何欄位上簡單地建立索引就能提高查詢速度。

從建表的語句中,我們可以看到這個有著1000萬數據的表中fariqi欄位有5003個不同記錄。在此欄位上建立聚合索引是再合適不過了。在現實中,我們每天都會發幾個文件,這幾個文件的發文日期就相同,這完全符合建立聚集索引要求的:「既不能絕大多數都相同,又不能只有極少數相同」的規則。由此看來,我們建立「適當」的聚合索引對於我們提高查詢速度是非常重要的。

3、把所有需要提高查詢速度的欄位都加進聚集索引,以提高查詢速度

上面已經談到:在進行數據查詢時都離不開欄位的是「日期」還有用戶本身的「用戶名」。既然這兩個欄位都是如此的重要,我們可以把他們合並起來,建立一個復合索引(compound index)。

很多人認為只要把任何欄位加進聚集索引,就能提高查詢速度,也有人感到迷惑:如果把復合的聚集索引欄位分開查詢,那麼查詢速度會減慢嗎?帶著這個問題,我們來看一下以下的查詢速度(結果集都是25萬條數據):(日期列fariqi首先排在復合聚集索引的起始列,用戶名neibuyonghu排在後列)

(1)select gid,fariqi,neibuyonghu,title from Tgongwen where fariqi>'2004-5-5'

查詢速度:2513毫秒

(2)select gid,fariqi,neibuyonghu,title from Tgongwen where fariqi>'2004-5-5' and neibuyonghu='辦公室'

查詢速度:2516毫秒

(3)select gid,fariqi,neibuyonghu,title from Tgongwen where neibuyonghu='辦公室'

查詢速度:60280毫秒

從以上試驗中,我們可以看到如果僅用聚集索引的起始列作為查詢條件和同時用到復合聚集索引的全部列的查詢速度是幾乎一樣的,甚至比用上全部的復合索引列還要略快(在查詢結果集數目一樣的情況下);而如果僅用復合聚集索引的非起始列作為查詢條件的話,這個索引是不起任何作用的。當然,語句1、2的查詢速度一樣是因為查詢的條目數一樣,如果復合索引的所有列都用上,而且查詢結果少的話,這樣就會形成「索引覆蓋」,因而性能可以達到最優。同時,請記住:無論您是否經常使用聚合索引的其他列,但其前導列一定要是使用最頻繁的列。

(四)其他書上沒有的索引使用經驗總結

1、用聚合索引比用不是聚合索引的主鍵速度快

下面是實例語句:(都是提取25萬條數據)

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

使用時間:3326毫秒

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid<=250000

使用時間:4470毫秒

這里,用聚合索引比用不是聚合索引的主鍵速度快了近1/4。

2、用聚合索引比用一般的主鍵作order by時速度快,特別是在小數據量情況下

select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by fariqi

用時:12936

select gid,fariqi,neibuyonghu,reader,title from Tgongwen order by gid

用時:18843

這里,用聚合索引比用一般的主鍵作order by時,速度快了3/10。事實上,如果數據量很小的話,用聚集索引作為排序列要比使用非聚集索引速度快得明顯的多;而數據量如果很大的話,如10萬以上,則二者的速度差別不明顯。

3、使用聚合索引內的時間段,搜索時間會按數據占整個數據表的百分比成比例減少,而無論聚合索引使用了多少個

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-1-1'

用時:6343毫秒(提取100萬條)

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-6-6'

用時:3170毫秒(提取50萬條)

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

用時:3326毫秒(和上句的結果一模一樣。如果採集的數量一樣,那麼用大於號和等於號是一樣的)

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-1-1' and fariqi<'2004-6-6'

用時:3280毫秒

4 、日期列不會因為有分秒的輸入而減慢查詢速度

下面的例子中,共有100萬條數據,2004年1月1日以後的數據有50萬條,但只有兩個不同的日期,日期精確到日;之前有數據50萬條,有5000個不同的日期,日期精確到秒。

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi>'2004-1-1' order by fariqi

用時:6390毫秒

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi<'2004-1-1' order by fariqi

用時:6453毫秒

(五)其他注意事項

「水可載舟,亦可覆舟」,索引也一樣。索引有助於提高檢索性能,但過多或不當的索引也會導致系統低效。因為用戶在表中每加進一個索引,資料庫就要做更多的工作。過多的索引甚至會導致索引碎片。

所以說,我們要建立一個「適當」的索引體系,特別是對聚合索引的創建,更應精益求精,以使您的資料庫能得到高性能的發揮。

當然,在實踐中,作為一個盡職的資料庫管理員,您還要多測試一些方案,找出哪種方案效率最高、最為有效。

二、改善SQL語句

很多人不知道SQL語句在SQL SERVER中是如何執行的,他們擔心自己所寫的SQL語句會被SQL SERVER誤解。比如:

select * from table1 where name='zhangsan' and tID > 10000

和執行:

select * from table1 where tID > 10000 and name='zhangsan'

一些人不知道以上兩條語句的執行效率是否一樣,因為如果簡單的從語句先後上看,這兩個語句的確是不一樣,如果tID是一個聚合索引,那麼後一句僅僅從表的10000條以後的記錄中查找就行了;而前一句則要先從全表中查找看有幾個name='zhangsan'的,而後再根據限制條件條件tID>10000來提出查詢結果。

事實上,這樣的擔心是不必要的。SQL SERVER中有一個「查詢分析優化器」,它可以計算出where子句中的搜索條件並確定哪個索引能縮小表掃描的搜索空間,也就是說,它能實現自動優化。

雖然查詢優化器可以根據where子句自動的進行查詢優化,但大家仍然有必要了解一下「查詢優化器」的工作原理,如非這樣,有時查詢優化器就會不按照您的本意進行快速查詢。

在查詢分析階段,查詢優化器查看查詢的每個階段並決定限制需要掃描的數據量是否有用。如果一個階段可以被用作一個掃描參數(SARG),那麼就稱之為可優化的,並且可以利用索引快速獲得所需數據。

SARG的定義:用於限制搜索的一個操作,因為它通常是指一個特定的匹配,一個值得范圍內的匹配或者兩個以上條件的AND連接。形式如下:

列名 操作符 <常數 或 變數>



<常數 或 變數> 操作符列名

列名可以出現在操作符的一邊,而常數或變數出現在操作符的另一邊。如:

Name=』張三』

價格>5000

5000<價格

Name=』張三』 and 價格>5000

如果一個表達式不能滿足SARG的形式,那它就無法限制搜索的范圍了,也就是SQL SERVER必須對每一行都判斷它是否滿足WHERE子句中的所有條件。所以一個索引對於不滿足SARG形式的表達式來說是無用的。

介紹完SARG後,我們來總結一下使用SARG以及在實踐中遇到的和某些資料上結論不同的經驗:

1、Like語句是否屬於SARG取決於所使用的通配符的類型

如:name like 『張%』 ,這就屬於SARG

而:name like 『%張』 ,就不屬於SARG。

原因是通配符%在字元串的開通使得索引無法使用。

2、or 會引起全表掃描

Name=』張三』 and 價格>5000 符號SARG,而:Name=』張三』 or 價格>5000 則不符合SARG。使用or會引起全表掃描。

3、非操作符、函數引起的不滿足SARG形式的語句

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

ABS(價格)<5000

Name like 『%三』

有些表達式,如:

WHERE 價格*2>5000

SQL SERVER也會認為是SARG,SQL SERVER會將此式轉化為:

WHERE 價格>2500/2

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

4、IN 的作用相當與OR

語句:

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



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

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

5、盡量少用NOT

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

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

(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前面加上通配符%,那麼將會引起全表掃描,所以其執行效率是低下的。但有的資料介紹說,用函數charindex()來代替LIKE速度會有大的提升,經我試驗,發現這種說明也是錯誤的:

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

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

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

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

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

我們前面已經談到了在where子句中使用or會引起全表掃描,一般的,我所見過的資料都是推薦這里用union來代替or。事實證明,這種說法對於大部分都是適用的。

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

用時: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

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

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

但經過試驗,筆者發現如果or兩邊的查詢列是一樣的話,那麼用union則反倒和用or的執行速度差很多,雖然這里union掃描的是索引,而or掃描的是全表。

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

用時: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'

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

9、欄位提取要按照「需多少、提多少」的原則,避免「select *」

我們來做一個試驗:

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

H. 百萬數據下幾種SQL性能測試

由於在參與的實際項目中發現當mysql表的數據量達到百萬級時,普通SQL查詢效率呈直線下降,而且如果where中的查詢條件較多時,其查詢速度簡直無法容忍。曾經測試對一個包含400多萬條記錄(有索引)的表執行一條條件查詢,其查詢時間竟然高達40幾秒,相信這么高的查詢延時,任何用戶都會抓狂。因此如何提高sql語句查詢效率,顯得十分重要。以下是網上流傳比較廣泛的30種SQL查詢語句優化方法:
1、應盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。

2、對查詢進行優化,應盡量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。

3、應盡量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:
select id from t where num is null
可以在num上設置默認值0,確保表中num列沒有null值,然後這樣查詢:
select id from t where num=0