SQL比較重要的知識點

1.聚集索引和非聚集索引的區別

  Page是數據庫存儲的最小單位,聚集索引的葉節點存儲的是真正的數據頁;非聚集索引的葉節點存儲的是指向數據頁的索引鍵值和指針。

  索引鍵值存儲的就是建立索引的列的值(字段值)
  SQLServer獲取數據,總是以頁爲單位,就算是隻讀取一行也會獲取整張頁
  僅非聚集索引--最終頁節點存儲的是索引鍵值和RID,其實也是一個一個的頁(Page)
  僅聚集索引--葉節點就是真正的數據頁(Page),頁中數據排序規則是按照索引鍵值進行排序
  索引中間頁--存儲的是索引的每一行,每一行存儲的是索引鍵值和指針(指針可能指向數據頁或者繼續指向中間頁)
  在既有聚集索引又有非聚集索引的情況下,每
個葉級節點所指向的是該聚集索引的索引鍵值,即數據記錄本身。

 

2.主鍵就是聚集索引嗎?

  開始設置的ID爲自動增長列,但是並未設置主鍵,在索引信息裏面沒看到有索引,接着設置了ID爲主鍵後,系統自動建立了索引。

有些文章說的是信息表並不適合建立主鍵,也就是不適合在ID列上建立索引,而是應該在經常要查詢的條件上建立聚集索引(某個字段)。

 

3.單一聚集索引和複合聚集索引的區別

   單一索引是指索引列爲一列的情況,即新建索引的語句只實施在一列上。

   用戶可以在多個列上建立索引,這種索引叫做複合索引(組合索引)。

   複合索引的創建方法與創建單一索引的方法完全一樣。但複合索引在數據庫操作期間所需的開銷更小,可以代替多個單一索引。當表的行數遠遠大於索引鍵的數目時,使用這種方式可以明顯加快表的查詢速度。窄索引是指索引列爲1-2列的索引,如果不特殊說明的話一般是指單一索引。寬索引也就是索引列超過2列的索引。設計索引的一個重要原則就是能用窄索引不用寬索引,因爲窄索引往往比組合索引更有效。

   建立複合索引的例子:

         CREATE UNIQUE CLUSTERED INDEX CLIDX_OrderDetails  ON dbo.OrderDetails(SalesOrderID,SalesOrderDetailID)

   如果僅用聚集索引的起始列作爲查詢條件和同時用到複合聚集索引的全部列的查詢速度是幾乎一樣的,甚至比用上全部的複合索引列還要略快(在查詢結果集數目一樣的情況下);而如果僅用複合聚集索引的非起始列作爲查詢條件的話,這個索引是不起任何作用的。無論您是否經常使用聚合索引的其他列,但其前導列一定要是使用最頻繁的列。

   (1)對一張表來說,如果有一個複合索引 on   (col1,col2),就沒有必要同時建立一個單索引 on col1。

  (2)如果查詢條件需要,可以在已有單索引 on col1的情況下,添加複合索引on   (col1,col2),對於效率有一定的提高。
  (3)
同時建立多字段(包含5、6個字段)的複合索引沒有特別多的好處,相對而言,建立多個窄字段(僅包含一個,或頂多2個字段)的索引可以達到更好的效率和靈活性。

 

4.不適合建立聚集索引的條件

   (1)頻繁更改的列.這將導致整行移動(因爲 SQL Server 必須按物理順序保留行中的數據值)。這一點要特別注意,因爲在大數據量事務處理系統中數據是易失的。

   (2)寬鍵.來自聚集索引的鍵值由所有非聚集索引作爲查找鍵使用,因此存儲在每個非聚集索引的葉條目內。

 

5.什麼時候適用於非聚集索引?

   (1)包含大量非重複值的列,如姓氏和名字的組合(如果聚集索引用於其它列)。如果只有很少的非重複值,如只有 1 和 0,則大多數查詢將不使用索引,因爲此時表掃描通常更有效。

   (2)不返回大型結果集的查詢。

   (3)返回精確匹配的查詢的搜索條件(WHERE 子句)中經常使用的列。

   (4)經常需要聯接和分組的決策支持系統應用程序。應在聯接和分組操作中使用的列上創建多個非聚集索引,在任何外鍵列上創建一個聚集索引。

   (5)在特定的查詢中覆蓋一個表中的所有列。這將完全消除對錶或聚集索引的訪問。

   索引都是一種排序,只是聚集索引的排序和物理表中的數據排序相同,一致的;而非聚集索引的排序和物理表數據的排序不同。

 

    當我們在更新統計信息的時候,對於那些聚集索引列不但要更新索引頁還要同時對數據物理表數據重新排序;而對非聚集索引列則只需要更新索引頁。

 

 

6.索引碎片的整理

   索引碎片是這樣一種情形:由於在表裏大量的插入、修改、刪除操作而使索引頁分裂。如果索引有了高的碎片,有兩種情況,一種情況是掃描索引需要花費很多的時間,另一種情況是在查詢的時候索引根本不使用索引,都會導致性能降低。

 

  有2種類型的碎片:

  內部破碎:由於索引頁裏的數據插入或修改操作而發生,以數據作爲稀疏矩陣的形式的分佈而結束,這將導致數據頁的增加,從而增加查詢時間。

  外部破碎:由於索引/數據頁的數據插入或修改而發生,以頁碼分離和在文件系統裏不連貫的新的索引頁的分配而結束,數據庫服務器不能利用預讀操作的優點,因爲:下一個相關聯的數據頁不臨近,而且這些相關連的下面的頁碼可能在數據文件的任何地方。

 

  檢測是否有碎片的方法:

    (1)以你的目標數據庫的名字取代AdventureWorks

  SELECT object_name(dt.object_id) Tablename,si.name, 

  IndexName,dt.avg_fragmentation_in_percent AS
  ExternalFragmentation,dt.avg_page_space_used_in_percent AS
  InternalFragmentation
  FROM
  (
  SELECT object_id,index_id,avg_fragmentation_in_percent,avg_page_space_used_in_percent
  FROMsys.dm_db_index_physical_stats(db_id('AdventureWorks'),null,null,null,'DETAILED'
  )
  WHERE index_id<>0)AS dt INNERJOIN sys.indexessiONsi.object_id=dt.object_id
  AND si.index_id=dt.index_id AND dt.avg_fragmentation_in_percent>10
  AND dt.avg_page_space_used_in_percent<75 ORDERBY avg_fragmentation_in_percentDESC

 

   ExternalFragmentation的值>10,預示對應的索引出現外部碎片。InternalFragmentation的值<75,預示對應的索引出現內部碎片

 

   (2)ShowPlan_All

        顯示查詢計劃是SQL在執行查詢的過程中查看哪些索引被採用,可以設置查詢計劃的開關On Off

        set showplan_all on
        go
        select * from admin_t

        go
        set showplan_all off

   (3)Statistics Io

         數據查詢過程中出現的磁盤活動量,也是性能的表現之一,可以設置開關On Off

         set statistics io on
         go
         select * from admin_t
         go
         set statistics io off

         (1 行受影響)
         表 'admin_t'。掃描計數 1,邏輯讀取 2 次,物理讀取 0 次,預讀 0 次,lob 邏輯讀取 0 次,lob 物理讀取 0 次,lob 預讀 0 次

 

  索引的維護

 在創建索引之後,隨着時間的推移,由於用戶對錶的添加刪除更新等,使得數據變得雜亂無序,影響索引的性能,所以需要經常對索引進行整理,更新。

(1)統計信息更新

我們在創建索引的時候,SQL會存儲有關的統計信息。因爲查詢優化器會根據統計信息進行查詢的成本進行計算,所以,如果統計信息過時了就會導致查詢優化器的查詢方法不是最優的。

我們一般對索引進行更新的方法語句是:update statistics admin_t PK_admin_t 中間是空格 不是點 .

(2)使用DBCC SHOWCONTIG語句掃描表

對錶進行操作可能會產生碎片,而碎片可能會產生額外的頁,從而降低數據查詢性能。通過掃描表查詢並通過返回值確定改索引的連續性達到多少,理想值是100%。

Dbcc Showcontig (admin_t,PK_admin_t) 是ShowContig 不是 ShowConfig,主要看他的掃描密度:

----------------------------------------------------------------

DBCC SHOWCONTIG 正在掃描 'admin_t' 表...
表: 'admin_t' (181575685);索引 ID: 1,數據庫 ID: 5
已執行 TABLE 級別的掃描。
- 掃描頁數................................: 1
- 掃描區數..............................: 1
- 區切換次數..............................: 0
- 每個區的平均頁數........................: 1.0
- 掃描密度 [最佳計數:實際計數].......: 100.00% [1:1]
- 邏輯掃描碎片 ..................: 0.00%
- 區掃描碎片 ..................: 0.00%
- 每頁的平均可用字節數........................: 8010.0
- 平均頁密度(滿).....................: 1.04%
DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯繫。


(3)碎片整理DBCC INDEXDEFRAG

出現了嚴重的碎片,就要進行整理。dbcc indexdefrag(study,admin_t,PK_admin_t)

和掃描不同,他要加上數據庫參數,是數據庫--表--索引

在使用碎片進行整理的時候如果報這樣的錯誤:無法重新組織表 "T_Info" 的索引 "T_S_Name_Index" (分區 1),因爲已禁用頁級鎖定。只要在索引的屬性中--選項--在訪問索引時啓用頁鎖 選中就可以了。

 

 

  接着重新整理索引碎片:

   (1)索引重組:執行 ALTER INDEX ALL ON TableName RECOGNIZE

   (2)索引重建:執行 ALTER INDEX ALL ON TableName REBUILD WITH(FILLFACTOR=90,=ON)

          通過使用具體索引的名字代替ALL,你能重組或重建單個的索引。你也可以使用數據庫控制檯來重建/重組索引

 

   什麼時候建立索引重組還是重建索引

    當外部碎片的值在10-15,內部碎片的值在60-75,對於這樣的索引,你應該重組索引。否則,你應該重建索引。

    關於索引重建的一個重要的事情是:一旦在一個特定的表上重建索引,表就會被鎖定(重組的時候不會發生)。所以,對於一個產品數據庫  的一個大的表,因爲在一個大表上的索引重建往往需要花費數個小時,我們不希望這種鎖定。幸運的是,在SQL2005有一個解決方法,你可  以在重建一個表的索引的時候,把ONLINE選項的值設爲ON,這樣會使重建索引和表上的數據事務同樣進行。

    規則建議:
   如果你在從事一個事務性數據庫,平均不要在一個表上創建超過5個索引,另外,如果你在從事數據倉庫,平均最高可在一個表上創建10個   索引。

 

 7.數據分區

   表分區分爲水平分區和垂直分區。水平分區將表分爲多個表。每個表包含的列數相同,但是行更少。例如,可以將一個包含十億行的表水平分區成 12 個表,每個小表表示特定年份內一個月的數據。任何需要特定月份數據的查詢只需引用相應月份的表。而垂直分區則是將原始表分成多個只包含較少列的表。水平分區是最常用分區方式

 

    分區文件格式

       數據文件可以分爲主數據文件和次數據文件:
主數據文件 擴展名爲 .mdf 其包含數據庫的啓動信息和數據信息。
次數據文件 擴展名爲 .ndf 其包含主數據文件沒有包含的數據信息
使用次數據文件可以將數據分散在多個磁盤上以提高讀取速度。如果數據庫很大,大到單個數據文件大小超過單個WINDOWS文件的最大 大小時,就必須要使用次要數據文件,以便可以讓數據庫繼續增長。
FAT16(Windows):支持最大分區2GB,最大文件2GB
FAT32(Windows):支持最大分區128GB,最大文件4GB
NTFS(Windows):支持最大分區2TB,最大文件2TB

 

    查看文件組信息:select * from sys.filegroups   其中is_read_only : 1 = 文件組爲只讀文件組 0=文件組爲可讀/寫的文件組

 

    分區實例:

    大綱:

(1)創建邏輯文件組

(2)創建次要數據文件(ndf文件)並隸屬文件組

(3)設置數據分區函數

(4)創建分區方案

(5)創建設置表

(6)查詢數據在分區裏面的詳細統計信息

下面進行詳細的設置:

1>創建文件組

alter database Study Add FileGroup [Study_1]

alter database Study Add FileGroup [Study_2]

alter database Study Add FileGroup [Study_3]

alter database Study Add FileGroup [Study_4]

2>設置文件到文件組

alter database Sudy Add File(Name=N'Stydu_1',FileName=N'd:/Study_1_F.ndf',Size=5M,FileGrowth=1M) TO FileGroup [Study_1]

alter database Sudy Add File(Name=N'Stydu_2',FileName=N'e:/Study_2_F.ndf',Size=5M,FileGrowth=1M) TO FileGroup [Study_2]

alter database Sudy Add File(Name=N'Stydu_3',FileName=N'f:/Study_3_F.ndf',Size=5M,FileGrowth=1M) TO FileGroup [Study_3]

alter database Sudy Add File(Name=N'Stydu_4',FileName=N'g:/Study_4_F.ndf',Size=5M,FileGrowth=1M) TO FileGroup [Study_4]

爲了保持高效率的數據讀寫,儘量每個次要數據文件放在不同的磁盤陣列上。

3>創建分區函數

表進行分區的標準是通過分區函數來實現的。創建分區函數有Range Left 和Range Right兩種情況,Range Left表示分區的上邊界;Range Right表示分區的下邊界。比如,你設置了四個分區,對於臨界點,倘若你設置上邊界可以這樣設置:

create partition function [BookListF] (datetime) As Range Left For values ('20090131','20090228','20090331','20090430')

注意裏面的時間段設置:

20090131--表示第一個分區的數據存放的是截止到2009-01-31的數據

20090228--表示第二個分區的數據存放的是截止到2009-02-28的數據

20090331--表示第三個分區的數據存放的是截止到2009-03-31的數據

20090430--表示第四個分區的數據存放的是截止到2009-04-30的數據

假如你設置下邊界可以這樣設置

create partition function [BookListF](datetime) As Range Right for values ('20090101','20090201','20090301')

注意裏面的時間設置:

20090101--表示第一個分區的數據存放的是從2009-01-01開始截止到2009-02-01的數據

20090201--表示第一個分區的數據存放的是從2009-02-01開始截止到2009-03-01的數據

20090301--表示第一個分區的數據存放的是從2009-03-01開始的數據

從上面的分區設置我們就能看出不同的邊界方式,設置的臨界點數不同,還有需要注意的一點是:比如從2009-01-01開始表示的是從2009-01-01 00:00:00的數據,截止到2009-02-01的數據表示的是截止到2009-01-31 23:59:59

4>創建分區方案

create partition scheme [BookListS] As partition [BookListF] To([Study_1],[Study_2],[Study_3],[Study_4])

創建分區方案其實也就是定義存放數據的媒體和數據塊之間的關係。多個數據表可以共同使用一個分區函數,但是不會共用相同的分區方案。

我們可以通過不同的分區方案使用相同的分區函數,使得不同的數據表有相同的分區條件,但是存放在不同的媒介上。

5>創建需要分區的數據表

create table TBook

(intID [int] IDENTITY[1,1] not null,

Description [varchar](100) null,

TDate [datetime] not null

)

on [BookListS](TDate)

注意最後一句:創建表綁定分區方案,並對應日期字段TDate

6>添加測試數據

insert into TBook values('11111','2009-01-02')

insert into TBook values('22222','2009-02-02')

insert into TBook values('33333','2009-03-02')

insert into TBook values('44444','2009-04-02')

insert into TBook values('55555','2009-01-02')


7>查詢數據在分區的體現

SELECT $partition.BookListF(o.TDate)
AS [Partition Number]
, min(o.TDate) AS [Min Date]
, max(o.TDate) AS [Max Date]
, count(*) AS [Rows In Partition]
FROM dbo.TBook AS o
GROUP BY $partition.BookListF(o.TDate)
ORDER BY [Partition Number]

在出現的結果裏在裏面就能看到每個分區有多少記錄(Rows In Patition對應的值),分區數(Partition Number)

 


8>撤銷刪除上面創建的信息

--刪除表

drop table TBook

--刪除分區方案

drop partition scheme [BookListS]

--刪除分區函數

drop partition function [BookListF]

--刪除文件和文件組

use master

alter database Study remove File [Study_1] --注意不是FileName的值,而是Name的值

alter database Study remove File [Study_2]

alter database Study remove File [Study_3]

alter database Study remove File [Study_4]

--刪除文件組

alter database Study remove FileGroup [Study_1]

alter database Study remove FileGroup [Study_2]

alter database Study remove FileGroup [Study_3]

alter database Study remove FileGroup [Study_4]

有人可能會說,我現在的數據庫中已經存在表了,要是還想分區怎麼實現呢?這個其實更簡單,你設置文件和文件組、創建分區函數、創建分區方案,就可以了,此時數據庫中的數據就會按照你創建的文件保存進去了。你可以創建好分區方案之後,添加一部分數據,然後查詢就能看到數據已經在不同的分區中了。

舉例:未創建分區之前T-info中有5條記錄

現在插入數據:insert into T_Info(CreateTime) values('2009-07-02')

由於臨界點是20090701,並且採用的是Range Right方式,所以正常情況下,數據會保存在第二分區

SELECT $partition.[StudyFun](o.CreateTime)
AS [Partition Number]
, min(o.CreateTime) AS [Min SendDate]
, max(o.CreateTime) AS [Max SendDate]
, count(*) AS [Rows In Partition]
FROM dbo.T_Info AS o
GROUP BY $partition.[StudyFun](o.CreateTime)
ORDER BY [Partition Number]

查詢結果如下圖:顯示在第二分區1條記錄 

        只是不能針對某個表進行限制,也就是說數據庫內的所有表都進行了分區,怎麼對單個表進行分區呢?

 

 8.Sql模糊查詢Like的新方式

    比如查找用戶名包含有"c"的所有用戶, 可以用
use mydatabase
select * from table1 where username like'%c%"


下面是完成上面功能的另一種寫法:
use mydatabase
select * from table1 where charindex('c',username)>0

這種方法理論上比上一種方法多了一個判斷語句,即>0, 但這個判斷過程是最快的, 我想信80%以上的運算都是花在查找字符串及其它的運算上, 所以運用charindex函數也沒什麼大不了. 用這種方法也有好處, 那就是對%,|等在不能直接用like查找到的字符中可以直接在這charindex中運用, 如下:

use mydatabase
select * from table1 where charindex('%',username)>0

也可以寫成:

use mydatabase
select * from table1 where charindex(char(37),username)>0

char(37) 的ASCII的字符即爲:%

 

9.從外到內提高SQL Server數據庫性能

 

      第一層:網絡環境。

  到企業碰到數據庫反映速度比較慢時,首先想到的是是否是網絡環境所造成的。而不是一開始就想着如何去提高數據庫的性能。這是很多數據庫管理員的一個誤區。因爲當網絡環境比較惡劣時,你就算再怎麼去改善數據庫性能,也是枉然。

  如以前有個客戶,向筆者反映數據庫響應時間比較長,讓筆者給他們一個提高數據庫性能的解決方案。那時,筆者感到很奇怪。因爲據筆者所知,這家客戶數據庫的記錄量並不是很大。而且,他們配置的數據庫服務器硬件很不錯。筆者爲此還特意跑到他們企業去查看問題的原因。一看原來是網絡環境所造成的。這家企業的客戶機有200多臺,而且都是利用集線器進行連接。這就導致企業內部網絡廣播氾濫,網絡擁塞。而且由於沒有部署企業級的殺毒軟件,網絡內部客戶機存在病毒,掠奪了一定的帶寬。不僅數據庫系統響應速度比較慢,而且其他應用軟件,如郵箱系統,速度也不理想。

  在這種情況下,即使再花十倍、百倍力氣去提升SQL Server數據庫的性能,也是竹籃子打水一場空。因爲現在數據庫服務器的性能瓶頸根本不在於數據庫本身,而在於企業的網絡環境。若網絡環境沒有得到有效改善,則SQL Server數據庫性能是提高不上去的。

  爲此,筆者建議這家企業,想跟他們的網絡管理員談談,看看如何改善企業的網絡環境,減少廣播包和網絡衝突;並且有效清除局域網內的病毒、木馬等等。三個月後,我再去回訪這家客戶的時候,他們反映數據庫性能有了很大的提高。而且其他應用軟件,性能也有所改善。

  所以,當企業遇到數據庫性能突然降低的時候,第一個反應就是查看網絡環境,看看其實否有惡化。只有如此,纔可以少走冤枉路。

  第二層:服務器配置。

  這裏指的服務器配置,主要是講數據庫服務器的硬件配置以及周邊配套。雖然說,提高數據庫的硬件配置,需要企業付出一定的代價。但是,這往往是一個比較簡便的方法。比起優化SQL語句來說,其要簡單的多。

  如企業可以通過增加硬盤的數量來改善數據庫的性能。在實際工作中,硬盤輸入輸出瓶頸經常被數據庫管理員所忽視。其實,到併發訪問比較多的時候,硬盤輸入輸出往往是數據庫性能的一個主要瓶頸之一。此時,若數據庫管理員可以增加幾個硬盤,通過磁盤陣列來分散磁盤的壓力,無疑是提高數據庫性能的一個捷徑。

  如增加服務器的內存或者CPU。當數據庫管理員發現數據庫性能的不理想是由內存或者CPU所造成的,此時,任何的改善數據庫服務器本身的措施都將一物用處。所以,有些數據庫管理專家,把改善服務器配置當作數據庫性能調整的一個先決條件。

  如解決部署在同一個數據庫服務器上的資源爭用問題。雖然我們多次強調,要爲數據庫專門部署一個服務器。但是,不少企業爲了降低信息化的成本,往往把數據庫服務器跟應用服務器放在同一個服務器中。這就會導致不同服務器之間的資源爭用問題。如把文件服務器跟數據服務器部署在同一個服務器中,當對文件服務器進行備份時,數據庫性能就會有明顯的下降。所以,在數據庫性能發現週期性的變化時,就要考慮是否因爲服務器上不同應用對資源的爭奪所造成的。

  故,筆者建議,改善數據庫性能時第二個需要考慮的層面,就是要看看能否通過改善服務器的配置來實現。


第三層:數據庫服務器。

  當通過改善網絡環境或者提高服務器配置,都無法達到改善數據庫性能的目的時,接下去就需要考察數據庫服務器本身了。首先,就需要考慮數據庫服務器的配置。

  一方面,要考慮數據庫服務器的連接模式。SQL Server數據庫提供了很多的數據庫模式,不同的數據庫連接模式對應不同的應用。若數據庫管理員能夠熟悉企業自身的應用,並且選擇合適的連接模式,這往往能夠達到改善數據庫性能的目的。

  其次,合理配置數據庫服務器的相關作業。如出於安全的需要,數據庫管理員往往需要對數據庫進行備份。那麼,備份的作業放在什麼時候合適呢?當然,放在夜晚,夜深人靜的時候,對數據庫進行備份最好。另外,對於大型數據庫,每天都進行完全備份將會是一件相當累人的事情。雖然累得不是我們,可是數據庫服務器也會吃不消。差異備份跟完全備份結合將是改善數據庫性能的一個不錯的策略。

  第四層:數據庫對象。

  若以上三個層面後,數據庫性能還不能夠得到大幅度改善的話,則就需要考慮是否能夠調整數據庫對象來完成我們的目的。雖然調整數據庫對象往往可以提到不錯的效果,但是,往往會對數據庫產生比較大的影響。所以,筆者一般不建議用戶一開始就通過調整數據庫對象來達到改善數據庫性能的目的。

  數據庫對象有表、視圖、索引、關鍵字等等。我們也可以通過對這些對象進行調整以實現改善數據庫性能的目標。

  如在視圖設計時,儘量把其顯示的內容縮小,寧可多增加視圖。如出貨明細表,銷售人員可能希望看到產品編號、產品中英文描述、產品名字、出貨日期、客戶編號、客戶名字等等。但是,對於財務來說,可能就不需要這麼全的信息。他們只需要產品編號、客戶編號、出貨日期等等少量的信息即可。所以,能可浪費一點代碼的空間,設計兩張視圖,對應不同部門的需求。如此,財務部門在查詢數據時,不會爲不必要的數據浪費寶貴的資源。

  如可以通過合理設置索引來提高數據庫的性能。索引對於提高數據的查詢效率,有着非常好的效果。對一些需要重複查詢的數據、或者數據修改不怎麼多的表設置索引,無疑是一個不錯的選擇。

  另外,要慎用存儲過程。雖然說存儲過程可以幫助大家實現很多需求。但是,在萬不得已的情況下,不要使用存儲過程。而利用前臺的應用程序來實現需求。這主要是因爲在通常情況下,前臺應用程序的執行效率往往比後臺數據庫存儲過程要高的多。

  第五層:SQL 語句。

  若以上各個層面你都努力過,但是還不滿足由此帶來的效果的話,則還有最後一招。通過對SQL語句進行優化,也可以達到改善數據庫性能的目的。

  雖然說SQL Server服務器自身就帶有一個SQL語句優化器。他會對用戶的SQL語句進行調整、優化,以達到一個比較好的執行效果。但是,據筆者的瞭解,這個最多隻能夠優化一些粗略的層面。或者說,80%的優化仍然需要數據庫管理員的配合。要數據庫管理員跟SQL優化器進行配合,才能夠起到非常明顯的作用。

  不過,SQL語句的調整對於普通數據庫管理員來說,可能有一定的難度。除非受過專業的訓練,一般很難對SQL語句進行優化。還好筆者受過這方面的專業訓練,對這方面有比較深的認識。如在SQL語句中避免使用直接量。任何一個包含有直接量的SQL語句都不太可能被再次使用。我們數據庫管理員要學會利用主機變量來代替直接量。不然,這些不可再用的查詢語句將使得程序緩存被不可再用的SQL語句填滿。這都是平時工作中的一些小習慣。

  總之,筆者認爲,在數據庫性能調優的時候,若能夠遵循如上的順序,必定可以讓我們少走冤枉路,不花無用功。其實,數據庫調優並沒有我們想象的這麼難。只要我們能夠掌握其中的訣竅,數據庫調優將可以手到擒來。


讀後感:學習到的知識點如下:

1、對數據庫的優化不僅僅是數據庫還要看其網絡環境以及機器的配置

2、對數據庫的備份不能每次都是完全備份,要和差異備份結合使用【要了解並掌握這些備份的方法以及區別】

3、對數據庫對象的優化,比如視圖,我們儘量減少那些不必要的字段,寧可多增加一個視圖

 

10.數據庫恢復with move參數

     我們在數據庫恢復的過程中,不一定都一定用到with move參數,只有在把數據還原到其他新的數據庫的時候,並重新定義數據庫文件地址 用到。

RESTORE DATABASE testdb FROM DISK = 'E:/20091124141351.bak'
WITH MOVE 'myData' TO 'f:/testdb.mdf',
MOVE 'myData_log' TO 'f:/testdb.ldf'

有個數據庫備份文件爲20091124141351.bak,那麼現在想還原這個數據庫爲新的數據庫並且數據文件存放到F盤下面並且主數據文件爲testdb.mdf,次數據文件爲testdb.ldf。

結果成功執行!打開F盤就能看到數據文件了。

 

 

11.淺談簡單恢復模式下的備份

      SQL Server數據庫備份模式簡單來說可以分爲完整恢復模式下的備份與簡單恢復模式下的備份。兩種不同的備份模式各有特點。筆者認爲數據庫管理員要清楚這兩種備份模式的差異,並結合企業的實際情況選擇合適的備份模式。筆者在這篇文章中,主要是想和各位專家討論下一下簡單恢復模式下的備份方式的優缺點以及相關的管理要點。就當作拋磚引玉,期待與各位專家共同成長。
  一、 簡單恢復模式的優點。

  簡單恢復模式下的備份就如同這個名字一樣,管理起來非常簡單。因爲在簡單恢復模式下的備份,始終不會備份事務日誌,故管理員來非常的方便。在簡單恢復模式下,數據庫系統會自動截斷事務日誌,以刪除所有不活動的虛擬日誌文件。截斷通常發生在每個檢查點之後。故不會對數據更新產生不利的影響。當數據庫的更新頻率比較高時,由於簡單恢復模式下的備份方式始終不會備份事務日誌,故其備份的效率會比較高。

  爲此,筆者在數據庫設計的時候,由於需要頻繁的變更數據庫的結構,需要創建新表或者調整相關參數。此時爲了節省數據庫備份的時間,筆者往往是採用簡單恢復模式下的備份。當有重要的變更後,就即使對數據庫進行備份。由於備份的時間間隔比較短,故不備份事務日誌不會產生多大的負面影響。反而可以提高數據庫的備份效率。

  二、 簡單恢復模式的缺點。

  簡單恢復模式下的備份最大的缺點就是可能導致最近數據備份之後所做的更新將會全部丟失。如現在有一個SQL Server數據庫系統。在今天凌晨1點剛完成一個差異備份。而在上午企業上班的時候,企業用戶通過前臺客戶端在系統中錄入了不少的銷售訂單、採購訂單等信息。可是不幸的是,在下午1點的時候數據庫突然出現了故障。經檢查是因爲數據庫的硬盤出現了不明原因的損壞。還有數據庫管理員採用了異地備份。故馬上採用了新硬盤並利用異地備份文件恢複相關的數據。但是由於採用了簡單恢復模式下的備份,此時就遇到了一個文件。因爲簡單恢復下的備份方式不會備份事務日誌。故在數據庫恢復的時候,只能夠恢復到凌晨1點的那個時刻的數據。上午上班員工錄入的銷售訂單、採購訂單等信息都無法恢復。此時員工只有重新建立這些信息。

  魚與熊掌不能夠兼得。簡單恢復模式下的備份方式始終不用備份事務日誌,故可以提供能比較快的備份速度。但是也正是因爲如此,數據庫在遇到故障時需要恢復的話,不能夠恢復到故障的那個點上。爲此數據庫管理員需要權衡利弊,選擇一個合適的備份方式。據筆者的個人經驗而言,簡單恢復模式並不適合用在生產系統上。因爲對於大部分生產系統而言,丟失數據庫的最新更改很可能用戶是無法接受的。因爲數據更改丟失很難找回,或者需要花費大量的時間補入。而數據庫備份的時間,數據庫管理元可以通過備份策略,把數據庫備份作業放到晚上進行。此時用戶使用數據庫比較少,即使備份需要花費幾個小時的時間,對用戶的影響也不會很大。故對於生產系統而言,特別是更改比較頻繁的生產系統,筆者是建議採用完整恢復模式,而不是這篇文章所講述的簡單恢復模式。

  三、 簡單恢復模式的管理要點。

  從上面的分析中,大家可以看出簡單恢復模式下的備份具有比較大的侷限性。但是畢竟其管理方便、備份效率高,在一些特定的場合還是經常被數據庫管理員所採用。現在的問題是,數據庫管理員該採取一些怎麼樣的策略,把這個侷限性降低到最低。筆者的做法是,提高差異備份的頻率,對簡單恢復模式下的備份方法進行補充,從而減少因爲沒有備份事務日誌而造成的數據丟失的風險。

  差異備份基於數據的最新完整備份而延伸出來的一種備份策略。這稱爲差異的基準。差異基準是讀、寫數據的完整備份。差異備份僅包含自建立差異基準後發生更改的數據。通常,建立基準備份之後很短時間內執行的差異備份比完整備份的基準更小,備份速度也更快。因爲差異備份只對上次備份以後的變更數據進行備份。故使用差異備份可以加快進行頻繁備份的速度,從而降低數據丟失的風險。通常,一個差異基準會由若干個相繼的差異備份使用。還原時,首先還原完整備份,然後再還原最新的差異備份。經過一段時間後,隨着數據庫的更新,包含在差異備份中的數據量會增加。這使得創建和還原備份的速度變慢。因此,必須重新創建一個完整備份,爲另一系列的差異備份提供新的差異基準。可見完全備份與差異備份結合使用,可以有效的降低簡單恢復模式下的數據丟失風險。

  通常情況下,差異備份所涵蓋的數據文件與單個差異基準中所涵蓋的文件相同。在簡單恢復模式下,一個差異備份只能有一個差異基準。嘗試使用多個基準會引發錯誤,並且備份操作將會失敗。不過根據筆者的經驗來看,一個差異備份只能有一個差異基準,基本上能夠滿足企業數據備份的需求。使用多基準差異備份反而會增加數據備份與恢復的難度,容易出錯。故無論企業採用的是何種備份模式,筆者都建議用戶儘量不要採用多基準差異備份。

可見差異備份與完整備份結合應用,並適當提高差異備份的頻率,可以降低因爲沒有別分事務日誌所造成的風險。但是這隻能夠起到降低的作用,而無法完全避免。如在上午10點時數據庫做了一個差異備份。但是到下午1點是數據庫出現了損壞。此時如果數據庫管理員還原數據庫的話,也只能夠恢復到上午10點時(差異備份發生時)的數據。而恢復不到下午1點時故障發生時的數據。也就是說,上午十點到下午一點這幾個小時中發生的數據變更將會丟失。可見簡單恢復模式下的備份方案由於始終沒備份事務日誌,由此帶來的數據損失風險無法避免。對於這一點,數據庫管理元一定要銘記於心。

  創建 SQL Server 備份的目的是爲了可以恢復已損壞的數據庫。但是,備份和還原數據必須根據特定環境進行自定義,並且必須使用可用資源。故如果結合數據庫資源來考慮,並不能夠說簡單恢復模式下的備份策略不好。如果企業比較看重備份的速率,而對於數據丟失的風險在一定程度之內可以忍受的話,那麼簡單恢復模式下的備份策略還是比較適合這種情況的。

  四、 簡單恢復模式下的備份總結

  簡單恢復模式下的備份跟完整備份模式或者大容量日誌備份模式的差異主要體現在事務日誌備份上。簡單恢復模式下的備份始終不會對事務日誌進行備份,故最新備份之後的更改將不受保護。在發生數據庫故障後,這些更改用戶必須手工的重新做一遍。即利用備份文件只能夠恢復到備份的結尾,而不能夠恢復到數據庫故障的時點上。而簡單完整備份模式下的最大優點是數據庫系統會回收日誌空間以減少硬盤空間的需求,或者說數據庫管理元不需要再管理事務日誌空間。同時其進行數據庫備份的時間也會大大縮短。

 

12.SQL2000異地備份數據

    /*
第一步:
在SQL server中做映射網絡盤
192.169.116.2爲遠程備份機
administrator爲遠程備份機登錄用戶名
111111爲遠程機器密碼
bak爲完全共享的文件夾
注意:(Z:後面要有一個空格)*/
exec master..xp_cmdshell 'net use z: //192.169.116.2/bak "111111" /user:192.169.116.2/administrator'

/*第二步:進行刪除前四日的數據庫備份文件*/
declare @myBackupName varchar(200)
set @myBackupName = 'del z:/fst_center' + convert(varchar(10),GETDATE()-4,112) + '.dat'
exec master..xp_cmdshell @myBackupName

/*第三步:進行當天的數據庫備份*/
declare @MyDataName varchar(200)
set @MyDataName='z:/fst_center' + convert(varchar(10),GETDATE(),112) + '.dat'
backup database fst_center1 to disk=@MyDataName

/*第四步:備份完成後刪除映射*/
exec master..xp_cmdshell 'net use z: /delete'


語法:

此命令的語法是:
NULL
NET USE
[devicename | *] [//computername/sharename[/volume] [password | *]]
[/USER:[domainname/]username]
[/USER:[dotted domain name/]username]
[/USER:[username@dotted domain name]
[/SMARTCARD]
[/SAVECRED]
[[/DELETE] | [/PERSISTENT:{YES | NO}]]
NULL
NET USE {devicename | *} [password | *] /HOME
NULL
NET USE [/PERSISTENT:{YES | NO}]
NULL
NULL

exec exec master..xp_cmdshell'net use //192.10.10.22/D$ "1234" /USER:192.10.10.22/administrator' master..xp_cmdshell'net use //192.10.10.22/D$ "1234" /USER:192.10.10.22/administrator'

 

13.Sql 2005數據庫的sa密碼忘記了怎麼辦?

     sp_password Null,'123,'sa'
     把sa的密碼設爲"123"

     執行成功後有"Command(s) completed successfully." OK!

 

14.數據庫日誌文件很大時清空日誌

      DUMP TRANSACTION 庫名 WITH NO_LOG

 

15.Sql2005內部函數/存儲過程/以及數據庫角色

 

     獲得當前ID的最頂級父類ID

============================================= 
-- Description: <獲得當前ID的最頂級ID>
-- =============================================
CREATE FUNCTION getParentID(@ID int)
RETURNS int
AS
BEGIN
declare @BackID int
declare @TempTab table(TempID int)
insert into @TempTab select T_ID from T_Type where T_ID=@ID
while @@rowcount<>0
begin
insert into @TempTab
select T.T_Parent from T_Type T inner Join @TempTab A on T.T_ID=A.TempID where T.T_Parent<>0 and T.T_Parent not in (select TempID from @TempTab)
end
set @BackID=(Select Top 1 TempID from @TempTab order by TempID asc)
return @BackID
END
GO

select dbo.getParentID(29)--調用查看

 

 

       獲得當前id所有的下級信息(自定義函數)

       SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE FUNCTION  [dbo].[F_AreaId](@ID VARCHAR(50))

RETURNS TABLE

AS

RETURN(WITH Temp_Area(id,AreName,ParentID)

AS (SELECT id,AreName,ParentID FROM Easy_Area WHERE  ID = @ID AND AreStatus = 1

UNION ALL 

SELECT a.id,a.AreName,a.ParentID FROM Easy_Area a INNER JOIN Temp_Area t ON(A.ParentID = t.id)

)

SELECT id,AreName,ParentID FROM Temp_Area

);

      /*日期函數*/
DATEADD ( datepart , number, date )
--在向指定日期加上一段時間的基礎上,返回新的 datetime 值。
DATEDIFF ( datepart , startdate , enddate )
--返回跨兩個指定日期的日期和時間邊界數。
DATENAME ( datepart , date )
--返回代表指定日期的指定日期部分的字符串。
DATEPART ( datepart , date )
--返回代表指定日期的指定日期部分的整數。
DAY ( date )
--返回代表指定日期的天的日期部分的整數。
GETDATE ( )
--按 datetime 值的 Microsoft? SQL Server? 標準內部格式返回當前系統日期和時間。
GETUTCDATE()
--返回表示當前 UTC 時間(世界時間座標或格林尼治標準時間)的 datetime 值。
--當前的 UTC 時間得自當前的本地時間和運行 SQL Server 的計算機操作系統中的時區設置。
MONTH ( date )
--返回代表指定日期月份的整數。
YEAR ( date )
--返回表示指定日期中的年份的整數。

Sql Server中的日期與時間函數
1. 當前系統日期、時間
select getdate()

2. dateadd 在向指定日期加上一段時間的基礎上,返回新的 datetime 值
例如:向日期加上2天
select dateadd(day,2,'2004-10-15') --返回:2004-10-17 00:00:00.000

3. datediff 返回跨兩個指定日期的日期和時間邊界數。
select datediff(day,'2004-09-01','2004-09-18') --返回:17

4. datepart 返回代表指定日期的指定日期部分的整數。
SELECT DATEPART(month, '2004-10-15') --返回 10

5. datename 返回代表指定日期的指定日期部分的字符串
SELECT datename(weekday, '2004-10-15') --返回:星期五

6. day(), month(),year() --可以與datepart對照一下

select 當前日期=convert(varchar(10),getdate(),120)
,當前時間=convert(varchar(8),getdate(),114)

select datename(dw,'2004-10-15')

select 本年第多少周=datename(week,'2004-10-15')
,今天是周幾=datename(weekday,'2004-10-15')

函數 參數/功能
GetDate( ) 返回系統目前的日期與時間
DateDiff (interval,date1,date2) 以interval 指定的方式,返回date2 與date1兩個日期之間的差值 date2-date1
DateAdd (interval,number,date) 以interval指定的方式,加上number之後的日期
DatePart (interval,date) 返回日期date中,interval指定部分所對應的整數值
DateName (interval,date) 返回日期date中,interval指定部分所對應的字符串名稱


參數 interval的設定值如下:

值 縮 寫(Sql Server) (Access 和 ASP) 說明
Year Yy yyyy 年 1753 ~ 9999
Quarter Qq q 季 1 ~ 4
Month Mm m 月1 ~ 12
Day of year Dy y 一年的日數,一年中的第幾日 1-366
Day Dd d 日,1-31
Weekday Dw w 一週的日數,一週中的第幾日 1-7
Week Wk ww 周,一年中的第幾周 0 ~ 51
Hour Hh h 時0 ~ 23
Minute Mi n 分鐘0 ~ 59
Second Ss s 秒 0 ~ 59
Millisecond Ms - 毫秒 0 ~ 999


access 和 asp 中用date()和now()取得系統日期時間;其中DateDiff,DateAdd,DatePart也同是能用於Access和asp中,這些函數的用法也類似

舉例:
1.GetDate() 用於sql server :select GetDate()

2.DateDiff('s','2005-07-20','2005-7-25 22:56:32')返回值爲 514592 秒
DateDiff('d','2005-07-20','2005-7-25 22:56:32')返回值爲 5 天

3.DatePart('w','2005-7-25 22:56:32')返回值爲 2 即星期一(週日爲1,週六爲7)
DatePart('d','2005-7-25 22:56:32')返回值爲 25即25號
DatePart('y','2005-7-25 22:56:32')返回值爲 206即這一年中第206天
DatePart('yyyy','2005-7-25 22:56:32')返回值爲 2005即2005年


--------------------------------------------------------------------------
/*字符串處理函數*/
LCASE( )
LOWER( )
--將字符串轉換爲小寫字母
LTRIM( )
--刪除字符串前面的空格
SUBSTRING( )
--從字符串中提取一個或多個字符
UCASE( )
UPPER( )
--將字符串轉換爲大寫字母
ROUND( )
--將數字按指定的小數位數四捨五入
FLOOR( )
--將數字向下四捨五入爲最接近(最小)的整數
CEILING( )
--將數字向上四捨五入爲最接近的整數
DATALENGTH( )
--返回指定的表達式所用的字節數
--------------------------------------------------------------------------
USER( )
USER_NAME( )
--返回當前用戶名
CONVERT( )
--將數據從一種類型轉換爲另一種類型。
SOUNDEX( )
--爲可創建"近似"搜索的指定表達式返回 Soundex 代碼。
STR( )
--將數字數據轉換爲字符串,以便可以用文本運算符對其進行處理。
/*全局變量*/
@@CONNECTIONS
--服務器上次啓動以來創建的連接數
@@CPU_BUSY
--自 SQL Server 啓動至今,系統持續運行的毫秒數。
@@CURSOR_ROWS
--最近打開的遊標中的行數
@@DATEFIRST
--SET DATEFIRST 參數的當前值,該參數用於設置一個星期的第一天爲哪一天。
@@ERROR
--最後一個 T-SQL 錯誤的錯誤號
@@FETCH_STATUS
--如果最後一次提取的狀態爲成功狀態,則爲 0。如果出錯,則爲 -1
@@IDENTITY
--最後一次插入的標識值
@@LANGUAGE
--當前使用的語言的名稱
@@MAX_CONNECTIONS
--可以創建的同時連接的最大數
@@ROWCOUNT
--受上一個 SQL 語句影響的行數
@@SERVERNAME
--本地服務器的名稱
@@SERVICENAME
--該計算機上的 SQL 服務的名稱
@@TIMETICKS
--當前計算機上每指令週期的微秒數
@@TRANSCOUNT
--當前連接打開的事務數
@@VERSION
--SQL Server 的版本信息
-----------------------------------------------------------------------
/*存儲過程*/
sp_databases --列出服務器上的所有數據庫
sp_server_info --列出服務器信息,如字符集,版本和排列順序
sp_stored_procedures--列出當前環境中的所有存儲過程
sp_tables --列出當前環境中所有可以查詢的對象
sp_start_job --立即啓動自動化任務
sp_stop_job --停止正在執行的自動化任務
sp_password --添加或修改登錄帳戶的密碼
sp_configure --顯示(不帶選項)或更改(帶選項)當前服務器的全局配置設置
sp_help --返回表的列名,數據類型,約束類型等
sp_helptext --顯示規則,默認值,未加密的存儲過程,用戶定義的函數,
--觸發器或視圖的實際文本
sp_helpfile --查看當前數據庫信息
sp_dboption --顯示或更改數據庫選項
sp_detach_db --分離數據庫
sp_attach_db --附加數據庫
sp_addumpdevice --添加設備
sp_dropdevice --刪除設備
sp_pkeys --查看主鍵
sp_fkeys --查看外鍵
sp_helpdb --查看指定數據庫相關文件信息
sp_addtype --自建數據類型
sp_droptype --刪除自建數據類型
sp_rename --重新命名數據庫
sp_executesql --執行SQL語句
sp_addlogin --添加登陸
sp_droplogin --刪除登錄
sp_grantdbaccess --把用戶映射到登錄,即添加一個數據庫安全帳戶並授予塔訪問權限
sp_revokedbaccess--撤銷用戶的數據訪問權,即從數據庫中刪除一個安全帳戶
sp_addrole --添加角色
sp_addrolemember --向角色中添加成員,使其成爲數據庫角色的成員
sp_addsrvrolemember--修改登錄使其成爲固定服務器角色的成員
sp_grantlogin --允許使用組帳戶或系統用戶使用Windows身份驗證連接到SQL
sp_defaultdb --修改一個登錄的默認數據庫
sp_helpindex --用於查看錶的索引
sp_cursoropen --定義與遊標和遊標選項相關的SQL語句,然後生成遊標
sp_cursorfetch --從遊標中提取一行或多行
sp_cursorclose --關閉並釋放遊標
sp_cursoroption --設置各種遊標選項
sp_cursor --用於請求定位更新
sp_cursorprepare --把與遊標有關的T-SQL語句或批處理編譯成執行計劃,但並不創建遊標
sp_cursorexecute --從由sp_cursorprepare創建的執行計劃中創建並填充遊標
sp_cursorunprepare --廢棄由sp_cursorprepare生成的執行計劃
sp_settriggerorder --指定第一個或最後一個激發的、與表關聯的 AFTER 觸發器。在第一個
--和最後一個觸發器之間激發的 AFTER 觸發器將按未定義的順序執行
--------------------------------------------------------------------------------
/*服務器角色*/
sysadmin
--在 SQL Server 中進行任何活動。該角色的權限跨越所有其它固定服務器角色。
serveradmin
--配置服務器範圍的設置。
setupadmin
--添加和刪除鏈接服務器,並執行某些系統存儲過程(如 sp_serveroption)。
securityadmin
--管理服務器登錄。
processadmin
--管理在 SQL Server 實例中運行的進程。
dbcreator
--創建和改變數據庫。
diskadmin
--管理磁盤文件。
bulkadmin
--執行 BULK INSERT 語句。
/*數據庫角色*/
public
public 角色
--public 角色是一個特殊的數據庫角色,每個數據庫用戶都屬於它。public 角色:
--捕獲數據庫中用戶的所有默認權限。
--無法將用戶、組或角色指派給它,因爲默認情況下它們即屬於該角色。
--含在每個數據庫中,包括 master、msdb、tempdb、model 和所有用戶數據庫。
--無法除去。
db_owner
--進行所有數據庫角色的活動,以及數據庫中的其它維護和配置活動。
--該角色的權限跨越所有其它固定數據庫角色。
db_accessadmin
--在數據庫中添加或刪除 Windows NT 4.0 或 Windows 2000 組和用戶以及 SQL Server 用戶。
db_datareader
--查看來自數據庫中所有用戶表的全部數據。
db_datawriter
--添加、更改或刪除來自數據庫中所有用戶表的數據
db_ddladmin
--添加、修改或除去數據庫中的對象(運行所有 DDL)
db_securityadmin
--管理 SQL Server 2000 數據庫角色的角色和成員,並管理數據庫中的語句和對象權限
db_backupoperator
--有備份數據庫的權限
db_denydatareader
--拒絕選擇數據庫數據的權限
db_denydatawriter
--拒絕更改數據庫數據的權限

 

    由於登錄失敗無法啓動sqlserver代理服務的解決辦法

    以前一直是代理備份數據庫的。打開SSMS才知道代理服務停止了,點擊啓動服務出現如下錯誤:

錯誤代碼:1069, 由於登錄失敗無法啓動服務。

後來查了一些資料才解決了。原來是我以前測試的時候建立了一個用戶,現在代理啓動是以那個用戶啓動的,我現在以admin管理員的身份當然無法啓動服務。問題找到了,就好解決了。

打開服務控制管理器(在運行中,輸入services.msc),找到sqlserver代理服務-SQL Server Agent (WON-這裏是你的實例名稱)--屬性--登錄--瀏覽-找到你想運行的用戶即可。

 

   插入數據後如何獲得最大記錄編號

      我們都知道可以採用seletc @@identity的語句來實現,並且使用存儲過程的方式輸出參數,但是,這絕對是正確的嗎?我的答案是不一定!

我在網絡上也搜索了這方面的知識點,並且結合自己的實踐得出如下結論:
1、當表上存在觸發器(插入數據觸發)
2、非一個鏈接操作數據

具體是怎麼回事呢?下面來詳細的介紹。

在說明之前先創建一個測試表(存在自動編號的列),語句如下:
create table Test_Identity(intID int identity(1,1) not null,TestName varchar(50) null)

insert into Test_Identity default values
seletc @@identity
結果爲1
insert into Test_Identity default values
seletc scope_identity()
結果爲2

結論都是正確的,好,那麼我們開始測試下面的情況

一、先說觸發器

創建另外一個表,保存觸發器操作的數據
create table Test_Trigger(intID int identity(1,1) not null,Triggname varchar(50) null)

在表Test_Identity上穿件觸發器
create trigger _Trigger on dbo.Test_Identity for insert as
set nocount on
insert into Test_Trigger(Triggname) select TestName from inserted

開始測試數據
insert into Test_Identity default values
seletc @@identity

結果爲1,實際上結果應該爲3纔是正確的

insert into Test_Identity default values
seletc scope_identity()
結果爲4,結論正確

二、當前非一個鏈接操作
由於沒辦法截圖,其實想下就知道,採用seletc @@identity方式肯定不行,返回的結果有可能是錯誤的。

 

    Sql語句從右開始查找字符串

            我們一般使用substring()對字符串進行截取,但是如果想從右側進行截取的話,可以對字段反轉過來

select top 10 REVERSE(substring(REVERSE(FileUrl),1,4)) from T_Table

REVERSE(FileUrl)--反轉字段

substring(REVERSE(FileUrl),1,4)--截取4位

REVERSE(substring(REVERSE(FileUrl),1,4)) --再次反轉

最後就是我們要用到的數據了

比如:UpFiles/200803_5003501060120080300440100444152.doc

最後得的結果是 .doc

 

   Sql語句中字符串和日期之間的轉換

     我們經常對日期進行轉換,一般是對日期進行轉換成字符串然後再對字符串進行格式化操作。

比如:update T_Gknb set T_Date=replace(convert(varchar(14),CreateTime,111),'/','-')

convert(varchar(14),CreateTime,111)--日期轉化爲14位的字符串

replace(convert(varchar(14),CreateTime,111),'/','-')--替換字符串中的 / 爲 -

日期轉換的規則如下:

convert(datatype,expression,[style])

style參數默認顯示的是年度2位,比如--yy(08,09)

如果想設置4位年度顯示方式,請再加上100,即

2位--4位--輸入輸出方式

0 100 mon dd yyyy hh:miAM(或PM)
1 101 mm/dd/yy
2 102 yymmdd
3 103 dd/mm/yy
4 104 ddmmyy
5 105 ddmmyy
6 106 dd mon yy
7 107 mon dd,yy
8 108 hh:mm:ss
9 109 mon dd yyyy hh:mi:ss:mmmmAM(或PM)
10 110 mmddyy
11 111 yy/mm/dd
12 112 yymmdd
13 113 dd mon yyyy hh:mi:ss:mmm(24小時制)
14 114 hh:mi:ss:mmm(24小時制)
20 120 yyyymmdd hh:mi:ss(24小時制)
21 121 yyyymmdd hh:mi:ss:mmm(24小時制)

舉例:

select CONVERT(varchar, getdate(), 120 )
2004-09-12 11:06:08

select replace(replace(replace(CONVERT(varchar, getdate(), 120 ),'-',''),' ',''),':','')
20040912110608

select CONVERT(varchar(12) , getdate(), 111 )
2004/09/12

select CONVERT(varchar(12) , getdate(), 112 )
20040912

select CONVERT(varchar(12) , getdate(), 102 )
2004.09.12

select CONVERT(varchar(12) , getdate(), 101 )
09/12/2004

select CONVERT(varchar(12) , getdate(), 103 )
12/09/2004

select CONVERT(varchar(12) , getdate(), 104 )
12.09.2004

select CONVERT(varchar(12) , getdate(), 105 )
12-09-2004

select CONVERT(varchar(12) , getdate(), 106 )
12 09 2004

select CONVERT(varchar(12) , getdate(), 107 )
09 12, 2004

select CONVERT(varchar(12) , getdate(), 108 )
11:06:08

select CONVERT(varchar(12) , getdate(), 109 )
09 12 2004 1

select CONVERT(varchar(12) , getdate(), 110 )
09-12-2004

select CONVERT(varchar(12) , getdate(), 113 )
12 09 2004 1

select CONVERT(varchar(12) , getdate(), 114 )
11:06:08.177

 

關於事務阻塞顯示數據問題

      兩個知識點
1、ReadPast--相當於歷史數據
2、NoLock--未鎖定的數據

不知道理解的是否正確
我親自測試了這些方法,先執行事務形成阻塞,然後查詢

begin transaction

insert into Tab values('12121')

--先執行事務,並且事務不關閉


select * from Tab --由於阻塞無法顯示
select * from Tab(ReadPast)--能顯示數據,只是是舊的數據
select * from Tab(NoLock)--能顯示數據,並且事務執行成功的數據也在裏面

如果我們在程序中加以應用,應該對系統有很大幫助

 

數據庫鎖定信息查詢

     如果想查詢數據庫系統爲什麼這麼慢,可以先看下是否有進程死鎖的現象。

exec sp_lock可以查詢系統進程信息列表

現在對每個字段進行詳細的解釋:

spid:系統進程標識碼。如果你想知道哪些用戶和此spid相連,那麼你可以通過exec sp_who spid進行查詢相關信息:exec sp_who 54

 

dbid:鎖定所發生的數據庫。你可以通過主數據庫master中的sysdatabases中找到對應的信息(dbid)

select * from sysdatabases 


objid:鎖定對象。你可在sysobjects表中查詢到相關的信息(id)。select * from sysobjects

在執行查詢的時候可能每次都不一樣,那是因爲有的鎖定已解除,或者新的鎖定添加了進來。如果你發現一個或者多個進程spID,一直存在,那麼這個進程就可能是處理比較大的過程了。

如果想知道當前佔用資源的進程的語句或者存儲過程在執行。可以通過DBCC INPUTBUFFER(SPID)查看。

這個DBCC命令將返回正在EventInfo字段中運行的語句的相關信息。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章