為了保證數據庫的壹致性和完整性,在邏輯設計中往往會設計過多的表關聯,以盡可能減少數據的冗余。(例如,用戶表中的區域可以存儲在另壹個區域表中。)如果數據冗余度低,則可以輕松保證數據完整性,這提高了數據吞吐速度,保證了數據完整性,並清晰地表達了數據元素之間的關系。不要將自增屬性字段用作與子表關聯的主鍵。不便於系統遷移和數據恢復。外部統計系統的映射關系丟失。
表格設計中應註意的問題:
1.數據線的長度不應超過8020字節。如果超過這個長度,這些數據將占據物理頁面中的兩行,從而導致存儲碎片並降低查詢效率。
2.您可以選擇數字類型而不是具有數字類型字段的字符串類型(電話號碼),這將降低查詢和連接的性能並增加存儲開銷。這是因為引擎在處理查詢並將其連接起來時會逐個比較字符串中的每個字符,而對於數值類型,只需比較壹次。
3.對於不可變字符類型char和可變字符類型varchar,兩者都是8000字節。char查詢速度很快,但會消耗存儲空間。varchar查詢相對較慢,但節省了存儲空間。設計字段時,可以靈活選擇。例如,您可以為用戶名和密碼等長度變化較小的字段選擇CHAR,為註釋等長度變化較大的字段選擇VARCHAR。
4.在最大程度滿足可能需求的前提下,字段的長度應設置得盡可能短,這樣可以提高查詢的效率,減少建立索引時的資源消耗。
二、查詢的優化
在數據窗口中使用SQL時,盡量將使用的索引放在選擇的第壹列;算法的結構盡可能簡單;
查詢時,不要使用太多通配符,如SELECT* FROM T1語句。如果要使用幾列,請選擇幾列如:select col1,col 2 from 1;盡量限制結果集中的行數,例如:select top 300 col1,col2,col 3 from 1,因為在某些情況下,用戶不需要那麽多數據。
在沒有索引的情況下,數據庫必須掃描整個表以找到某壹段數據,並遍歷所有數據壹次以找出符合條件的記錄。在數據量很小的情況下,可能沒有明顯的區別,但在數據量很大的情況下,這種情況是極其糟糕的。
在SQL SERVER中如何執行SQL語句?他們擔心他們的SQL語句會被SQLSERVER誤解。例如:
select * from table1其中name =‘Zhang San‘且tID & gt10000和執行:
select * from table1其中tID & gt10000 and name =‘張三‘
有些人不知道上面兩條語句的執行效率是否相同,因為如果簡單地看語句的順序,這兩條語句確實是不同的。如果tID是壹個聚合索引,那麽最後壹句只能從表中10000之後的記錄中找到。前壹句應該先從整個表中查找幾個name =‘Zhang San’,然後根據限制性條件tid》;10000來顯示查詢結果。
事實上,這種擔心是不必要的。SQLSERVER中有壹個查詢分析優化器,它可以計算where子句中的搜索條件,並確定哪個索引可以減少表掃描的搜索空間,即可以實現自動優化。雖然查詢優化器可以根據where子句自動優化查詢,但有時查詢優化器不會根據您的意圖快速查詢。
因此,優化查詢最重要的是使語句盡可能符合查詢優化器的規則,避免全表掃描和使用索引查詢。
應特別註意:
1.盡量避免判斷where子句中字段的空值,否則引擎將放棄使用索引並掃描整個表,例如:
從編號為空的t中選擇id
您可以將num的默認值設置為0,以確保表中的num列沒有空值,然後像這樣查詢它:
從t中選擇id,其中num=0
2.盡量避免在where子句中使用它!=或
3.盡量避免在where子句中使用or來連接條件,否則會導致引擎放棄使用索引並掃描整個表,例如:
從t中選擇id,其中數字=10或數字=20
您可以像這樣查詢:
從t中選擇id其中num=10
聯合所有
從編號=20s的t中選擇id
4.in和not in也應該謹慎使用,因為in會使系統無法使用索引,只能直接搜索表中的數據。比如:
select id from t where num in(1,2,3)
對於連續值,可以使用between而不是in:
從t中選擇id,其中數字介於1和3之間
6.如有必要,強制查詢優化器使用索引(如在where子句中使用參數)也將導致全表掃描。因為SQL只在運行時解析局部變量,所以優化器不能將訪問計劃的選擇推遲到運行時;必須在編譯時選擇它。但是,如果訪問計劃是在編譯時建立的,則變量的值仍然未知,因此它不能用作索引選擇的輸入項。以下語句將掃描整個表:
select id from t其中num=@num
您可以強制查詢改為使用索引:
用(index)從t中選擇id,其中num=@num。
7.盡量避免在where子句中對字段進行表達式操作,這將導致引擎放棄使用索引並掃描整個表。比如:
SELECT * FROM T1其中F1/2=100
應改為:
SELECT * FROM T1其中F1=100*2
SELECT * FROM RECORD where substring(CARD _ NO,1,4)=‘5378‘
應改為:
SELECT * FROM RECORD WHERE CARD _ NO LIKE‘5378%‘
從成員中選擇成員編號、名字、姓氏
其中DATEDIFF(YY,datofbirth,GETDATE())& gt;21
應改為:
從成員中選擇成員編號、名字、姓氏
其中出生日期& ltDATEADD(YY,-21,GETDATE())
也就是說,對列的任何操作都會導致表掃描,其中包括數據庫函數、計算表達式等。查詢時,盡可能將操作移至等號右側。
8.應盡可能避免對where子句中的字段進行函數操作,這將導致引擎放棄使用索引並掃描整個表。比如:
select id from where substring(name,1,3)= abc-以ABC開頭的名稱ID。
從其中datediff(日,創建日期,‘2005-11-30’)= 0-‘2005-11-30’生成的id中選擇id。
應改為:
從t中選擇id,其中名稱如“abc%”
從t where createdate & gt中選擇id。=‘2005-11-30‘和andcreatedate & lt'2005-12-1'
9.不要在where子句中的“=”左側執行函數、算術運算或其他表達式運算,否則系統可能無法正確使用索引。
10.當使用索引字段作為條件時,如果索引是復合索引,則必須將索引中的第壹個字段作為條件來確保系統使用該索引,否則該索引將不會被使用,並且字段順序應盡可能與索引順序壹致。
11.很多時候使用exists是壹個很好的選擇:
select num from a where num in(select num from b)
替換為以下語句:
從存在的a中選擇num(從b中選擇1,其中num=a.num)
但後者的效率明顯高於前者。因為後者不會產生大量的鎖定表掃描或索引掃描。
如果您想檢查表中是否有記錄,請不要使用count(*),這樣效率很低,而且會浪費服務器資源。可以使用EXISTS來代替。比如:
IF(SELECT COUNT(*)FROM table _ name WHERE column _ name =‘XXX‘)
可以寫成:
如果存在(SELECT * FROM table _ name WHERE column _ name =‘XXX‘)
12.盡量使用表變量而不是臨時表。如果表變量包含大量數據,請註意索引非常有限(只有主鍵索引)。
13.避免頻繁創建和刪除臨時表以減少系統表資源的消耗。
14.臨時表並非不可用。正確使用它們可以使壹些例程更加有效,例如,當需要重復引用大型表或公共表中的數據集時。但是,對於壹次性事件,最好使用導出表。
15.創建臨時表時,如果壹次插入大量數據,可以使用select into代替create table,以避免大量日誌並提高速度;如果數據量不大,為了緩解系統表的資源,應該先創建表再插入。
16.如果使用臨時表,必須在存儲過程結束時顯式刪除所有臨時表,首先truncate table table,然後drop table table,以避免長時間鎖定系統表。
17.在所有存儲過程和觸發器的開頭設置SET NOCOUNT ON,在結尾設置set SET NOCOUNT OFF。在執行存儲過程和觸發器的每個語句後,無需向客戶端發送DONE_IN_PROC消息。
18.盡量避免大型事務操作,提高系統並發性。
19.盡量避免向客戶端返回大量數據。如果數據量過大,則應考慮相應的要求是否合理。
20.避免使用不兼容的數據類型。例如,float和int、char和varchar、binary和varbinary是不兼容的。數據類型的不兼容可能會阻止優化器執行壹些本來可以完成的優化操作。例如:
從薪金& gt的員工中選擇姓名。60000
在該語句中,如果salary字段的類型是money,優化器很難對其進行優化,因為60000是壹個整數。我們應該在編程時將整數轉換為硬幣,而不是等待運行時轉換。
23.如果您可以使用DISTINCT,則不需要GROUP BY。
從單價》的詳細信息中選擇訂單ID。10按訂單ID分組
可以更改為:
從單價》的詳細信息中選擇不同的訂單ID。10
24.如果可以使用UNION ALL,請不要使用UNION。
UNION ALL不執行SELECTDISTINCT函數,這將減少大量不必要的資源。
35.盡量不要使用SELECT INTO語句。
SELECT INOT語句導致表被鎖定,從而阻止其他用戶訪問該表。
第四,建立有效的索引
創建索引通常有兩個目的:維護索引列的唯壹性和提供快速訪問表中數據的策略。
大型數據庫中有兩種索引,即聚集索引和非聚集索引。沒有聚集索引的表根據堆結構存儲數據,所有數據都添加在表的末尾。但是,具有聚集索引的表的數據將按照聚集索引鍵的順序存儲,並且壹個表中只允許有壹個聚集索引。因此,根據B樹結構,可以理解為添加任何索引都可以提高通過索引列進行查詢的速度,但會降低插入、更新和刪除操作的性能。因此,對索引較多的表進行頻繁的插入、更新和刪除操作,並在構建表和索引時設置較小的填充因子,以在每個數據頁中留下更多的空閑空間,並減少頁分割和重組的工作。
索引是從數據庫中獲取數據的最有效方法之壹。95%的數據庫性能問題可以通過索引技術解決。通常,我通常對邏輯主鍵使用唯壹的分組索引,對系統鍵使用唯壹的未分組索引(作為存儲過程),對任何外鍵列【字段】使用未分組索引。然而,指數就像鹽壹樣,太多的食物會使它變鹹。您必須考慮數據庫中有多少空間,如何訪問表,以及這些訪問是否主要用於讀寫。
事實上,您可以將索引視為壹種特殊的目錄。微軟的SQL SERVER提供兩種索引:clusteredindex和nonclusteredindex。
聚集索引和非聚集索引的區別:
事實上,我們的漢語詞典的文本本身就是壹個聚集索引。比如我們要查“安”這個字,自然會翻開字典的前幾頁,因為“安”的拼音是“an”,按拼音排序漢字的字典以英文字母“A”開頭,以“Z”結尾,所以“安”字自然排在字典的最前面。如果妳在查找了所有以“A”開頭的部分後都找不到該單詞,這意味著該單詞不在妳的字典中。同樣,如果妳查“張”這個字,妳也會翻到字典的最後壹部分,因為“張”的拼音是“zhang”。換句話說,字典本身的主體是壹個目錄,您不需要查找其他目錄來找到您需要查找的內容。
我們將這種文本內容本身稱為按照壹定規則排列的目錄“聚集索引”。
如果妳認識壹個單詞,妳可以很快地從自動詞典裏查出來。但是妳可能會遇到壹個妳不認識的單詞,妳不知道它的發音。這時候妳就找不到剛才想查的單詞了,而是需要根據偏旁查找妳想要的單詞,然後直接翻到壹頁根據單詞後面的頁碼找到妳想要的單詞。但是,妳結合部首目錄和字典找到的單詞的排序並不是文本的真正排序方法。例如,如果您查找“張”字,我們可以看到“張”字在部首搜索後在字典中的頁碼是672,“池”字在字典中的“張”字上方,但頁碼是63並在其下方。顯然,這些字並不是真的分別在“張”字的上面和下面。現在妳看到的連續詞“遲、張、弩”實際上是它們在非聚集索引中的排序,是詞典體中的詞在非聚集索引中的映射。我們可以通過這種方式找到您需要的單詞,但它需要兩個過程,首先在目錄中找到結果,然後轉向您需要的頁碼。