① 如何寫出高性能sql語句
1、 首先要搞明白什麼叫執行計劃?
執行計劃是資料庫根據SQL語句和相關表的統計信息作出的一個查詢方案,這個方案是由查詢優化器自動分析產生的,比如一條SQL語句如果用來從一個 10萬條記錄的表中查1條記錄,那查詢優化器會選擇「索引查找」方式,如果該表進行了歸檔,當前只剩下5000條記錄了,那查詢優化器就會改變方案,採用 「全表掃描」方式。
可見,執行計劃並不是固定的,它是「個性化的」。產生一個正確的「執行計劃」有兩點很重要:
(1) SQL語句是否清晰地告訴查詢優化器它想干什麼?
(2) 查詢優化器得到的資料庫統計信息是否是最新的、正確的?
2、 統一SQL語句的寫法
對於以下兩句SQL語句,程序員認為是相同的,資料庫查詢優化器認為是不同的。
select*from al
select*From al
其實就是大小寫不同,查詢分析器就認為是兩句不同的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語句的負擔。一次解析,多次重用,是提高資料庫效率的原則。
② 如何寫出高性能SQL語句
優化SQL查詢:如何寫出高性能SQL語句1、首先要搞明白什麼叫執行計劃?執行計劃是資料庫根據SQL語句和相關表的統計信息作出的一個查詢方案,這個方案是由查詢優化器自動分析產生欀如一條SQL語句如果用來從一個10萬條記錄的表中查1條記錄,那查詢優化器會選擇「索引查找」方式,如果該表進行了歸檔,當前只剩下5000條記錄了,那查詢優化器就會改變方案,採用「全表掃描」方式。可見,執行計劃並不是固定的,它是「個性化的」。產生一個正確的「執行計劃」有兩點很重要:(1)SQL語句是否清晰地告訴查詢優化器它想干什麼?(2)查詢優化器得到的資料庫統計信息是否是最新的、正確的?2、統一SQL語句的寫法對於以下兩句SQL語句,程序員認為是相同的,資料庫查詢優化器認為是不同的。select*fromalselect*Fromal其實就是大小寫不同,查詢分析器就認為是兩句不同的SQL語句,必須進行兩次解析。生成2個執行計劃。所以作為程序員,應該保證相同的查詢語句在任何地方都一致,多一個空格都不行!3、不要把SQL語句寫得太復雜我經常看到,從資料庫中捕捉到的一條SQL語句列印出來有2張A4紙這么長。一般來說這么復雜的語句通常都是有問題的。我拿著這2頁長的SQL語句去請教原作者,結果他說時間太長,他一時也看不懂了。可想而知,連原作者都有可能看糊塗的SQL語句,資料庫也一樣會看糊塗。一般,將一個Select語句的結果作為子集,然後從該子集中再進行查詢,這種一層嵌套語句還是比較常見的,但是根據經驗,超過3層嵌套,查詢優化器就很容易給出錯誤的執行計劃。因為它被繞暈了。像這種類似人工智慧的東西,終究比人的分辨力要差些,如果人都看暈了,我可以保證資料庫也會暈的。另外,執行計劃是可以被重用的,越簡單的SQL語句被重用的可能性越高。而復雜的SQL語句只要有一個字元發生變化就必須重新解析,然後再把這一大堆垃圾塞在內存里。可想而知,資料庫的效率會何等低下。4、使用「臨時表」暫存中間結果簡化SQL語句的重要方法就是採用臨時表暫存中間結果,但是,臨時表的好處遠遠不止這些,將臨時結果暫存在臨時表,後面的查詢就在tempdb中了,這可以避免程序中多次掃描主表,也大大減少了程序執行中「共享鎖」阻塞「更新鎖」,減少了阻塞,提高了並發性能。5、OLTP系統SQL語句必須採用綁定變數select*>』2010-10-2000:00:01′select*>』2010-09-2200:00:01′以上兩句語句,查詢優化器認為是不同的SQL語句,需要解析兩次。如果採用綁定變數select*>@chgtime@chgtime變數可以傳入任何值,這樣大量的類似查詢可以重用該執行計劃了,這可以大大降低資料庫解析SQL語句的負擔。一次解析,多次重用,是提高資料庫效率的原則。6、綁定變數窺測事物都存在兩面性,綁定變數對大多數OLTP處理是適用的,但是也有例外。比如在where條件中的欄位是「傾斜欄位」的時候。「傾斜欄位」指該列中的絕大多數的值都是相同的,一張人口調查表,其中「民族」這列,90%以上都是漢族。那麼如果一個SQL語句要查詢30歲的漢族人口有多少,那「民族」這列必然要被放在where條件中。這個時候如果採用綁定變數@nation會存在很大問題。試想如果@nation傳入的第一個值是「漢族」,那整個執行計劃必然會選擇表掃描。然後,第二個值傳入的是「布依族」,按理說「布依族」占的比例可能只有萬分之一,應該採用索引查找。但是,由於重用了第一次解析的「漢族」的那個執行計劃,那麼第二次也將採用表掃描方式。這個問題就是著名的「綁定變數窺測」,建議對於「傾斜欄位」不要採用綁定變數。7、只在必要的情況下才使用begintranSQLServer中一句SQL語句默認就是一個事務,在該語句執行完成後也是默認commit的。其實,這就是begintran的一個最小化的形式,好比在每句語句開頭隱含了一個begintran,結束時隱含了一個commit。有些情況下,我們需要顯式聲明begintran,比如做「插、刪、改」操作需要同時修改幾個表,要求要麼幾個表都修改成功,要麼都不成功。begintran可以起到這樣的作用,它可以把若干SQL語句套在一起執行,最後再一起commit。好處是保證了數據的一致性,但任何事情都不是完美無缺的。Begintran付出的代價是在提交之前,所有SQL語句鎖住的資源都不能釋放,直到commit掉。可見,如果Begintran套住的SQL語句太多,那資料庫的性能就糟糕了。在該大事務提交之前,必然會阻塞別的語句,造成block很多。Begintran使用的原則是,在保證數據一致性的前提下,begintran套住的SQL語句越少越好!有些情況下可以採用觸發器同步數據,不一定要用begintran。8、一些SQL查詢語句應加上nolock在SQL語句中加nolock是提高SQLServer並發性能的重要手段,在oracle中並不需要這樣做,因為oracle的結構更為合理,有undo表空間保存「數據前影」,該數據如果在修改中還未commit,那麼你讀到的是它修改之前的副本,該副本放在undo表空間中。這樣,oracle的讀、寫可以做到互不影響,這也是oracle廣受稱贊的地方。SQLServer的讀、寫是會相互阻塞的,為了提高並發性能,對於一些查詢,可以加上nolock,這樣讀的時候可以允許寫,但缺點是可能讀到未提交的臟數據。使用nolock有3條原則。(1)查詢的結果用於「插、刪、改」的不能加nolock!(2)查詢的表屬於頻繁發生頁分裂的,慎用nolock!(3)使用臨時表一樣可以保存「數據前影」,起到類似oracle的undo表空間的功能,能採用臨時表提高並發性能的,不要用nolock。9、聚集索引沒有建在表的順序欄位上,該表容易發生頁分裂比如訂單表,有訂單編號orderid,也有客戶編號contactid,那麼聚集索引應該加在哪個欄位上呢?對於該表,訂單編號是順序添加的,如果在orderid上加聚集索引,新增的行都是添加在末尾,這樣不容易經常產生頁分裂。然而,由於大多數查詢都是根據客戶編號來查的,因此,將聚集索引加在contactid上才有意義。而contactid對於訂單表而言,並非順序欄位。比如「張三」的「contactid」是001,那麼「張三」的訂單信息必須都放在這張表的第一個數據頁上,如果今天「張三」新下了一個訂單,那該訂單信息不能放在表的最後一頁,而是第一頁!如果第一頁放滿了呢?很抱歉,該表所有數據都要往後移動為這條記錄騰地方。SQLServer的索引和Oracle的索引是不同的,SQLServer的聚集索引實際上是對表按照聚集索引欄位的順序進行了排序,相當於oracle的索引組織表。SQLServer的聚集索引就是表本身的一種組織形式,所以它的效率是非常高的。也正因為此,插入一條記錄,它的位置不是隨便放的,而是要按照順序放在該放的數據頁,如果那個數據頁沒有空間了,就引起了頁分裂。所以很顯然,聚集索引沒有建在表的順序欄位上,該表容易發生頁分裂。曾經碰到過一個情況,一位哥們的某張表重建索引後,插入的效率大幅下降了。估計情況大概是這樣的。該表的聚集索引可能沒有建在表的順序欄位上,該表經常被歸檔,所以該表的數據是以一種稀疏狀態存在的。比如張三下過20張訂單,而最近3個月的訂單只有5張,歸檔策略是保留3個月數據,那麼張三過去的15張訂單已經被歸檔,留下15個空位,可以在insert發生時重新被利用。在這種情況下由於有空位可以利用,就不會發生頁分裂。但是查詢性能會比較低,因為查詢時必須掃描那些沒有數據的空位。重建聚集索引後情況改變了,因為重建聚集索引就是把表中的數據重新排列一遍,原來的空位沒有了,而頁的填充率又很高,插入數據經常要發生頁分裂,所以性能大幅下降。對於聚集索引沒有建在順序欄位上的表,是否要給與比較低的頁填充率?是否要避免重建聚集索引?是一個值得考慮的問題!10、加nolock後查詢經常發生頁分裂的表,容易產生跳讀或重復讀加nolock後可以在「插、刪、改」的同時進行查詢,但是由於同時發生「插、刪、改」,在某些情況下,一旦該數據頁滿了,那麼頁分裂不可避免,而此時nolock的查詢正在發生,比如在第100頁已經讀過的記錄,可能會因為頁分裂而分到第101頁,這有可能使得nolock查詢在讀101頁時重復讀到該條數據,產生「重復讀」。同理,如果在100頁上的數據還沒被讀到就分到99頁去了,那nolock查詢有可能會漏過該記錄,產生「跳讀」。上面提到的哥們,在加了nolock後一些操作出現報錯,估計有可能因為nolock查詢產生了重復讀,2條相同的記錄去插入別的表,當然會發生主鍵沖突。11、使用like進行模糊查詢時應注意有的時候會需要進行一些模糊查詢比如select*fromcontactwhereusernamelike『%yue%』關鍵詞%yue%,由於yue前面用到了「%」,因此該查詢必然走全表掃描,除非必要,否則不要在關鍵詞前加%,12、數據類型的隱式轉換對查詢效率的影響sqlserver2000的資料庫一的程序在提交sql語句的時候,沒有使用強類型提交這個欄位的值,由sqlserver2000自動轉換數據類型,會導致傳入的參數與主鍵欄位類型不一致,這個時候sqlserver2000可能就會使用全表掃描。Sql2005上沒有發現這種問題,但是還是應該注意一下。13、SQLServer表連接的三種方式(1)MergeJoin(2)NestedLoopJoin(3)HashJoinSQLServer2000隻有一種join方式——NestedLoopJoin,如果A結果集較小,那就默認作為外表,A中每條記錄都要去B中掃描一遍,實際掃過的行數相當於A結果集行數xB結果集行數。所以如果兩個結果集都很大,那Join的結果很糟糕。SQLServer2005新增了MergeJoin,如果A表和B表的連接欄位正好是聚集索引所在欄位,那麼表的順序已經排好,只要兩邊拼上去就行了,這種join的開銷相當於A表的結果集行數加上B表的結果集行數,一個是加,一個是乘,可見mergejoin的效果要比NestedLoopJoin好多了。如果連接的欄位上沒有索引,那SQL2000的效率是相當低的,而SQL2005提供了Hashjoin,相當於臨時給A,B表的結果集加上索引,因此SQL2005的效率比SQL2000有很大提高,我認為,這是一個重要的原因。總結一下,在表連接時要注意以下幾點:(1)連接欄位盡量選擇聚集索引所在的欄位(2)仔細考慮where條件,盡量減小A、B表的結果集(3)如果很多join的連接欄位都缺少索引,而你還在用SQLServer2000,趕緊升級吧。
③ sql語句,有的全要
SELECT --從資料庫表中檢索數據行和列
INSERT --向資料庫表添加新數據行
DELETE --從資料庫表中刪除數據行
UPDATE --更新資料庫表中的數據
--數據定義
CREATE TABLE --創建一個資料庫表
DROP TABLE --從資料庫中刪除表
ALTER TABLE --修改資料庫表結構
CREATE VIEW --創建一個視圖
DROP VIEW --從資料庫中刪除視圖
CREATE INDEX --為資料庫表創建一個索引
DROP INDEX --從資料庫中刪除索引
CREATE PROCEDURE --創建一個存儲過程
DROP PROCEDURE --從資料庫中刪除存儲過程
CREATE TRIGGER --創建一個觸發器
DROP TRIGGER --從資料庫中刪除觸發器
CREATE SCHEMA --向資料庫添加一個新模式
DROP SCHEMA --從資料庫中刪除一個模式
CREATE DOMAIN --創建一個數據值域
ALTER DOMAIN --改變域定義
DROP DOMAIN --從資料庫中刪除一個域
--數據控制
GRANT --授予用戶訪問許可權
DENY --拒絕用戶訪問
REVOKE --解除用戶訪問許可權
--事務控制
COMMIT --結束當前事務
ROLLBACK --中止當前事務
SET TRANSACTION --定義當前事務數據訪問特徵
--程序化SQL
DECLARE --為查詢設定游標
EXPLAN --為查詢描述數據訪問計劃
OPEN --檢索查詢結果打開一個游標
FETCH --檢索一行查詢結果
CLOSE --關閉游標
PREPARE --為動態執行准備SQL 語句
EXECUTE --動態地執行SQL 語句
DESCRIBE --描述准備好的查詢
---局部變數
declare @id char(10)
--set @id = '10010001'
select @id = '10010001'
---全局變數
---必須以@@開頭
--IF ELSE
declare @x int @y int @z int
select @x = 1 @y = 2 @z=3
if @x > @y
print 'x > y' --列印字元串'x > y'
else if @y > @z
print 'y > z'
else print 'z > y'
--CASE
use pangu
update employee
set e_wage =
case
when job_level = 』1』 then e_wage*1.08
when job_level = 』2』 then e_wage*1.07
when job_level = 』3』 then e_wage*1.06
else e_wage*1.05
end
--WHILE CONTINUE BREAK
declare @x int @y int @c int
select @x = 1 @y=1
while @x < 3
begin
print @x --列印變數x 的值
while @y < 3
begin
select @c = 100*@x + @y
print @c --列印變數c 的值
select @y = @y + 1
end
select @x = @x + 1
select @y = 1
end
--WAITFOR
--例 等待1 小時2 分零3 秒後才執行SELECT 語句
waitfor delay 』01:02:03』
select * from employee
--例 等到晚上11 點零8 分後才執行SELECT 語句
waitfor time 』23:08:00』
select * from employee
***SELECT***
select *(列名) from table_name(表名) where column_name operator value
ex:(宿主)
select * from stock_information where stockid = str(nid)
stockname = 'str_name'
stockname like '% find this %'
stockname like '[a-zA-Z]%' --------- ([]指定值的范圍)
stockname like '[^F-M]%' --------- (^排除指定范圍)
--------- 只能在使用like關鍵字的where子句中使用通配符)
or stockpath = 'stock_path'
or stocknumber < 1000
and stockindex = 24
not stocksex = 'man'
stocknumber between 20 and 100
stocknumber in(10,20,30)
order by stockid desc(asc) --------- 排序,desc-降序,asc-升序
order by 1,2 --------- by列號
stockname = (select stockname from stock_information where stockid = 4)
--------- 子查詢
--------- 除非能確保內層select只返回一個行的值,
--------- 否則應在外層where子句中用一個in限定符
select distinct column_name form table_name --------- distinct指定檢索獨有的列值,不重復
select stocknumber ,"stocknumber + 10" = stocknumber + 10 from table_name
select stockname , "stocknumber" = count(*) from table_name group by stockname
--------- group by 將表按行分組,指定列中有相同的值
having count(*) = 2 --------- having選定指定的組
select *
from table1, table2
where table1.id *= table2.id -------- 左外部連接,table1中有的而table2中沒有得以null表示
table1.id =* table2.id -------- 右外部連接
select stockname from table1
union [all] ----- union合並查詢結果集,all-保留重復行
select stockname from table2
***insert***
insert into table_name (Stock_name,Stock_number) value ("xxx","xxxx")
value (select Stockname , Stocknumber from Stock_table2)---value為select語句
***update***
update table_name set Stockname = "xxx" [where Stockid = 3]
Stockname = default
Stockname = null
Stocknumber = Stockname + 4
***delete***
delete from table_name where Stockid = 3
truncate table_name ----------- 刪除表中所有行,仍保持表的完整性
drop table table_name --------------- 完全刪除表
***alter table*** --- 修改資料庫表結構
alter table database.owner.table_name add column_name char(2) null .....
sp_help table_name ---- 顯示表已有特徵
create table table_name (name char(20), age smallint, lname varchar(30))
insert into table_name select ......... ----- 實現刪除列的方法(創建新表)
alter table table_name drop constraint Stockname_default ---- 刪除Stockname的default約束
***function(/*常用函數*/)***
----統計函數----
AVG --求平均值
COUNT --統計數目
MAX --求最大值
MIN --求最小值
SUM --求和
--AVG
use pangu
select avg(e_wage) as dept_avgWage
from employee
group by dept_id
--MAX
--求工資最高的員工姓名
use pangu
select e_name
from employee
where e_wage =
(select max(e_wage)
from employee)
--STDEV()
--STDEV()函數返回表達式中所有數據的標准差
--STDEVP()
--STDEVP()函數返回總體標准差
--VAR()
--VAR()函數返回表達式中所有值的統計變異數
--VARP()
--VARP()函數返回總體變異數
----算術函數----
/***三角函數***/
SIN(float_expression) --返回以弧度表示的角的正弦
COS(float_expression) --返回以弧度表示的角的餘弦
TAN(float_expression) --返回以弧度表示的角的正切
COT(float_expression) --返回以弧度表示的角的餘切
/***反三角函數***/
ASIN(float_expression) --返回正弦是FLOAT 值的以弧度表示的角
ACOS(float_expression) --返回餘弦是FLOAT 值的以弧度表示的角
ATAN(float_expression) --返回正切是FLOAT 值的以弧度表示的角
ATAN2(float_expression1,float_expression2)
--返回正切是float_expression1 /float_expres-sion2的以弧度表示的角
DEGREES(numeric_expression)
--把弧度轉換為角度返回與表達式相同的數據類型可為
--INTEGER/MONEY/REAL/FLOAT 類型
RADIANS(numeric_expression) --把角度轉換為弧度返回與表達式相同的數據類型可為
--INTEGER/MONEY/REAL/FLOAT 類型
EXP(float_expression) --返回表達式的指數值
LOG(float_expression) --返回表達式的自然對數值
LOG10(float_expression)--返回表達式的以10 為底的對數值
SQRT(float_expression) --返回表達式的平方根
/***取近似值函數***/
CEILING(numeric_expression) --返回>=表達式的最小整數返回的數據類型與表達式相同可為
--INTEGER/MONEY/REAL/FLOAT 類型
FLOOR(numeric_expression) --返回<=表達式的最小整數返回的數據類型與表達式相同可為
--INTEGER/MONEY/REAL/FLOAT 類型
ROUND(numeric_expression) --返回以integer_expression 為精度的四捨五入值返回的數據
--類型與表達式相同可為INTEGER/MONEY/REAL/FLOAT 類型
ABS(numeric_expression) --返回表達式的絕對值返回的數據類型與表達式相同可為
--INTEGER/MONEY/REAL/FLOAT 類型
SIGN(numeric_expression) --測試參數的正負號返回0 零值1 正數或-1 負數返回的數據類型
--與表達式相同可為INTEGER/MONEY/REAL/FLOAT 類型
PI() --返回值為π 即3.1415926535897936
RAND([integer_expression]) --用任選的[integer_expression]做種子值得出0-1 間的隨機浮點數
----字元串函數----
ASCII() --函數返回字元表達式最左端字元的ASCII 碼值
CHAR() --函數用於將ASCII 碼轉換為字元
--如果沒有輸入0 ~ 255 之間的ASCII 碼值CHAR 函數會返回一個NULL 值
LOWER() --函數把字元串全部轉換為小寫
UPPER() --函數把字元串全部轉換為大寫
STR() --函數把數值型數據轉換為字元型數據
LTRIM() --函數把字元串頭部的空格去掉
RTRIM() --函數把字元串尾部的空格去掉
LEFT(),RIGHT(),SUBSTRING() --函數返回部分字元串
CHARINDEX(),PATINDEX() --函數返回字元串中某個指定的子串出現的開始位置
SOUNDEX() --函數返回一個四位字元碼
--SOUNDEX函數可用來查找聲音相似的字元串但SOUNDEX函數對數字和漢字均只返回0 值
DIFFERENCE() --函數返回由SOUNDEX 函數返回的兩個字元表達式的值的差異
--0 兩個SOUNDEX 函數返回值的第一個字元不同
--1 兩個SOUNDEX 函數返回值的第一個字元相同
--2 兩個SOUNDEX 函數返回值的第一二個字元相同
--3 兩個SOUNDEX 函數返回值的第一二三個字元相同
--4 兩個SOUNDEX 函數返回值完全相同
QUOTENAME() --函數返回被特定字元括起來的字元串
/*select quotename('abc', '{') quotename('abc')
運行結果如下
----------------------------------{
{abc} [abc]*/
REPLICATE() --函數返回一個重復character_expression 指定次數的字元串
/*select replicate('abc', 3) replicate( 'abc', -2)
運行結果如下
----------- -----------
abcabcabc NULL*/
REVERSE() --函數將指定的字元串的字元排列順序顛倒
REPLACE() --函數返回被替換了指定子串的字元串
/*select replace('abc123g', '123', 'def')
運行結果如下
----------- -----------
abcdefg*/
SPACE() --函數返回一個有指定長度的空白字元串
STUFF() --函數用另一子串替換字元串指定位置長度的子串
----數據類型轉換函數----
CAST() 函數語法如下
CAST() (<expression> AS <data_ type>[ length ])
CONVERT() 函數語法如下
CONVERT() (<data_ type>[ length ], <expression> [, style])
select cast(100+99 as char) convert(varchar(12), getdate())
運行結果如下
------------------------------ ------------
199 Jan 15 2000
----日期函數----
DAY() --函數返回date_expression 中的日期值
MONTH() --函數返回date_expression 中的月份值
YEAR() --函數返回date_expression 中的年份值
DATEADD(<datepart> ,<number> ,<date>)
--函數返回指定日期date 加上指定的額外日期間隔number 產生的新日期
DATEDIFF(<datepart> ,<number> ,<date>)
--函數返回兩個指定日期在datepart 方面的不同之處
DATENAME(<datepart> , <date>) --函數以字元串的形式返回日期的指定部分
DATEPART(<datepart> , <date>) --函數以整數值的形式返回日期的指定部分
GETDATE() --函數以DATETIME 的預設格式返回系統當前的日期和時間
----系統函數----
APP_NAME() --函數返回當前執行的應用程序的名稱
COALESCE() --函數返回眾多表達式中第一個非NULL 表達式的值
COL_LENGTH(<'table_name'>, <'column_name'>) --函數返回表中指定欄位的長度值
COL_NAME(<table_id>, <column_id>) --函數返回表中指定欄位的名稱即列名
DATALENGTH() --函數返回數據表達式的數據的實際長度
DB_ID(['database_name']) --函數返回資料庫的編號
DB_NAME(database_id) --函數返回資料庫的名稱
HOST_ID() --函數返回伺服器端計算機的名稱
HOST_NAME() --函數返回伺服器端計算機的名稱
IDENTITY(<data_type>[, seed increment]) [AS column_name])
--IDENTITY() 函數只在SELECT INTO 語句中使用用於插入一個identity column列到新表中
/*select identity(int, 1, 1) as column_name
into newtable
from oldtable*/
ISDATE() --函數判斷所給定的表達式是否為合理日期
ISNULL(<check_expression>, <replacement_value>) --函數將表達式中的NULL 值用指定值替換
ISNUMERIC() --函數判斷所給定的表達式是否為合理的數值
NEWID() --函數返回一個UNIQUEIDENTIFIER 類型的數值
NULLIF(<expression1>, <expression2>)
--NULLIF 函數在expression1 與expression2 相等時返回NULL 值若不相等時則返回expression1 的值
--------------------------------------------------------------------------------
sql中的保留字
action add aggregate all
alter after and as
asc avg avg_row_length auto_increment
between bigint bit binary
blob bool both by
cascade case char character
change check checksum column
columns comment constraint create
cross current_date current_time current_timestamp
data database databases date
datetime day day_hour day_minute
day_second dayofmonth dayofweek dayofyear
dec decimal default delayed
delay_key_write delete desc describe
distinct distinctrow double drop
end else escape escaped
enclosed enum explain exists
fields file first float
float4 float8 flush foreign
from for full function
global grant grants group
having heap high_priority hour
hour_minute hour_second hosts identified
ignore in index infile
inner insert insert_id int
integer interval int1 int2
int3 int4 int8 into
if is isam join
key keys kill last_insert_id
leading left length like
lines limit load local
lock logs long longblob
longtext low_priority max max_rows
match mediumblob mediumtext mediumint
middleint min_rows minute minute_second
modify month monthname myisam
natural numeric no not
null on optimize option
optionally or order outer
outfile pack_keys partial password
precision primary procere process
processlist privileges read real
references reload regexp rename
replace restrict returns revoke
rlike row rows second
select set show shutdown
smallint soname sql_big_tables sql_big_selects
sql_low_priority_updates sql_log_off sql_log_update sql_select_limit
sql_small_result sql_big_result sql_warnings straight_join
starting status string table
tables temporary terminated text
then time timestamp tinyblob
tinytext tinyint trailing to
type use using unique
unlock unsigned update usage
values varchar variables varying
varbinary with write when
where year year_month zerofill
④ 如何寫出高性能SQL語句
優化SQL查詢:如何寫出高性能SQL語句
1、首先要搞明白什麼叫執行計劃?
執行計劃是資料庫根據SQL語句和相關表的統計信息作出的一個查詢方案,這個方案是由查詢優化器自動分析產生欀如一條SQL語句如果用來從一個10萬條
記錄的表中查1條記錄,那查詢優化器會選擇「索引查找」方式,如果該表進行了歸檔,當前只剩下5000條記錄了,那查詢優化器就會改變方案,採用 「全表
掃描」方式。
可見,執行計劃並不是固定的,它是「個性化的」。產生一個正確的「執行計劃」有兩點很重要:
(1) SQL語句是否清晰地告訴查詢優化器它想干什麼?
(2) 查詢優化器得到的資料庫統計信息是否是最新的、正確的?
2、統一SQL語句的寫法
對於以下兩句SQL語句,程序員認為是相同的,資料庫查詢優化器認為是不同的。
select * from al
select * From al
其實就是大小寫不同,查詢分析器就認為是兩句不同的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,趕緊升級吧。
⑤ 如何寫出高性能SQL語句
優化SQL查詢:如何寫出高性能SQL語句
1、首先要搞明白什麼叫執行計劃?
執行計劃是資料庫根據SQL語句和相關表的統計信息作出的一個查詢方案,這個方案是由查詢優化器自動分析產生欀如一條SQL語句如果用來從一個10萬條記錄的表中查1條記錄,那查詢優化器會選擇「索引查找」方式,如果該表進行了歸檔,當前只剩下5000條記錄了,那查詢優化器就會改變方案,採用 「全表掃描」方式。
可見,執行計劃並不是固定的,它是「個性化的」。產生一個正確的「執行計劃」有兩點很重要:
(1) SQL語句是否清晰地告訴查詢優化器它想干什麼?
(2) 查詢優化器得到的資料庫統計信息是否是最新的、正確的?
2、統一SQL語句的寫法
對於以下兩句SQL語句,程序員認為是相同的,資料庫查詢優化器認為是不同的。
select * from al
select * From al
其實就是大小寫不同,查詢分析器就認為是兩句不同的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,趕緊升級吧。
⑥ 如何寫出高性能SQL語句
優化SQL查詢:如何寫出高性能SQL語句
1、首先要搞明白什麼叫執行計劃?
執行計劃是資料庫根據SQL語句和相關表的統計信息作出的一個查詢方案,這個方案是由查詢優化器自動分析產生欀如一條SQL語句如果用來從一個10萬條記錄的表中查1條記錄,那查詢優化器會選擇「索引查找」方式,如果該表進行了歸檔,當前只剩下5000條記錄了,那查詢優化器就會改變方案,採用 「全表掃描」方式。
可見,執行計劃並不是固定的,它是「個性化的」。產生一個正確的「執行計劃」有兩點很重要:
(1) SQL語句是否清晰地告訴查詢優化器它想干什麼?
(2) 查詢優化器得到的資料庫統計信息是否是最新的、正確的?
2、統一SQL語句的寫法
對於以下兩句SQL語句,程序員認為是相同的,資料庫查詢優化器認為是不同的。
select * from al
select * From al
其實就是大小寫不同,查詢分析器就認為是兩句不同的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,趕緊升級吧。
⑦ SQL資料庫語句大全
經典SQL語句大全
下列語句部分是Mssql語句,不可以在access中使用。
SQL分類:
DDL—數據定義語言(CREATE,ALTER,DROP,DECLARE)
DML—數據操縱語言(SELECT,DELETE,UPDATE,INSERT)
DCL—數據控制語言(GRANT,REVOKE,COMMIT,ROLLBACK)
首先,簡要介紹基礎語句:
1、說明:創建資料庫
CREATE DATABASE database-name
2、說明:刪除資料庫
drop database dbname
3、說明:備份sql server
--- 創建 備份數據的 device
USE master
EXEC sp_admpdevice 'disk', 'testBack', 'c:\mssql7backup\MyNwind_1.dat'
--- 開始 備份
BACKUP DATABASE pubs TO testBack
4、說明:創建新表
create table tabname(col1 type1 [not null] [primary key],col2 type2 [not null],..)
根據已有的表創建新表:
A:create table tab_new like tab_old (使用舊表創建新表)
B:create table tab_new as select col1,col2… from tab_old definition only
5、說明:
刪除新表:drop table tabname
6、說明:
增加一個列:Alter table tabname add column col type
註:列增加後將不能刪除。DB2中列加上後數據類型也不能改變,唯一能改變的是增加varchar類型的長度。
7、說明:
添加主鍵:Alter table tabname add primary key(col)
說明:
刪除主鍵:Alter table tabname drop primary key(col)
8、說明:
創建索引:create [unique] index idxname on tabname(col….)
刪除索引:drop index idxname
註:索引是不可更改的,想更改必須刪除重新建。
9、說明:
創建視圖:create view viewname as select statement
刪除視圖:drop view viewname
10、說明:幾個簡單的基本的sql語句
選擇:select * from table1 where 范圍
插入:insert into table1(field1,field2) values(value1,value2)
刪除:delete from table1 where 范圍
更新:update table1 set field1=value1 where 范圍
查找:select * from table1 where field1 like 』%value1%』 ---like的語法很精妙,查資料!
排序:select * from table1 order by field1,field2 [desc]
總數:select count * as totalcount from table1
求和:select sum(field1) as sumvalue from table1
平均:select avg(field1) as avgvalue from table1
最大:select max(field1) as maxvalue from table1
最小:select min(field1) as minvalue from table1
11、說明:幾個高級查詢運算詞
A: UNION 運算符
UNION 運算符通過組合其他兩個結果表(例如 TABLE1 和 TABLE2)並消去表中任何重復行而派生出一個結果表。當 ALL 隨 UNION 一起使用時(即 UNION ALL),不消除重復行。兩種情況下,派生表的每一行不是來自 TABLE1 就是來自 TABLE2。
B: EXCEPT 運算符
EXCEPT 運算符通過包括所有在 TABLE1 中但不在 TABLE2 中的行並消除所有重復行而派生出一個結果表。當 ALL 隨 EXCEPT 一起使用時 (EXCEPT ALL),不消除重復行。
C: INTERSECT 運算符
INTERSECT 運算符通過只包括 TABLE1 和 TABLE2 中都有的行並消除所有重復行而派生出一個結果表。當 ALL 隨 INTERSECT 一起使用時 (INTERSECT ALL),不消除重復行。
註:使用運算詞的幾個查詢結果行必須是一致的。
12、說明:使用外連接
A、left outer join:
左外連接(左連接):結果集幾包括連接表的匹配行,也包括左連接表的所有行。
SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
B:right outer join:
右外連接(右連接):結果集既包括連接表的匹配連接行,也包括右連接表的所有行。
C:full outer join:
全外連接:不僅包括符號連接表的匹配行,還包括兩個連接表中的所有記錄。
其次,大家來看一些不錯的sql語句
1、說明:復製表(只復制結構,源表名:a 新表名:b) (Access可用)
法一:select * into b from a where 1<>1
法二:select top 0 * into b from a
2、說明:拷貝表(拷貝數據,源表名:a 目標表名:b) (Access可用)
insert into b(a, b, c) select d,e,f from b;
3、說明:跨資料庫之間表的拷貝(具體數據使用絕對路徑) (Access可用)
insert into b(a, b, c) select d,e,f from b in 『具體資料庫』 where 條件
例子:..from b in '"&Server.MapPath(".")&"\data.mdb" &"' where..
4、說明:子查詢(表名1:a 表名2:b)
select a,b,c from a where a IN (select d from b ) 或者: select a,b,c from a where a IN (1,2,3)
5、說明:顯示文章、提交人和最後回復時間
select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b
6、說明:外連接查詢(表名1:a 表名2:b)
select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
7、說明:在線視圖查詢(表名1:a )
select * from (SELECT a,b,c FROM a) T where t.a > 1;
8、說明:between的用法,between限制查詢數據范圍時包括了邊界值,not between不包括
select * from table1 where time between time1 and time2
select a,b,c, from table1 where a not between 數值1 and 數值2
9、說明:in 的使用方法
select * from table1 where a [not] in (『值1』,』值2』,』值4』,』值6』)
10、說明:兩張關聯表,刪除主表中已經在副表中沒有的信息
delete from table1 where not exists ( select * from table2 where table1.field1=table2.field1 )
11、說明:四表聯查問題:
select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where .....
12、說明:日程安排提前五分鍾提醒
SQL: select * from 日程安排 where datediff('minute',f開始時間,getdate())>5
13、說明:一條sql 語句搞定資料庫分頁
select top 10 b.* from (select top 20 主鍵欄位,排序欄位 from 表名 order by 排序欄位 desc) a,表名 b where b.主鍵欄位 = a.主鍵欄位 order by a.排序欄位
14、說明:前10條記錄
select top 10 * form table1 where 范圍
15、說明:選擇在每一組b值相同的數據中對應的a最大的記錄的所有信息(類似這樣的用法可以用於論壇每月排行榜,每月熱銷產品分析,按科目成績排名,等等.)
select a,b,c from tablename ta where a=(select max(a) from tablename tb where tb.b=ta.b)
16、說明:包括所有在 TableA 中但不在 TableB和TableC 中的行並消除所有重復行而派生出一個結果表
(select a from tableA ) except (select a from tableB) except (select a from tableC)
17、說明:隨機取出10條數據
select top 10 * from tablename order by newid()
18、說明:隨機選擇記錄
select newid()
19、說明:刪除重復記錄
Delete from tablename where id not in (select max(id) from tablename group by col1,col2,...)
20、說明:列出資料庫里所有的表名
select name from sysobjects where type='U'
21、說明:列出表裡的所有的
select name from syscolumns where id=object_id('TableName')
22、說明:列示type、vender、pcs欄位,以type欄位排列,case可以方便地實現多重選擇,類似select 中的case。
select type,sum(case vender when 'A' then pcs else 0 end),sum(case vender when 'C' then pcs else 0 end),sum(case vender when 'B' then pcs else 0 end) FROM tablename group by type
顯示結果:
type vender pcs
電腦 A 1
電腦 A 1
光碟 B 2
光碟 A 2
手機 B 3
手機 C 3
23、說明:初始化表table1
TRUNCATE TABLE table1
24、說明:選擇從10到15的記錄
select top 5 * from (select top 15 * from table order by id asc) table_別名 order by id desc
隨機選擇資料庫記錄的方法(使用Randomize函數,通過SQL語句實現)
對存儲在資料庫中的數據來說,隨機數特性能給出上面的效果,但它們可能太慢了些。你不能要求ASP「找個隨機數」然後列印出來。實際上常見的解決方案是建立如下所示的循環:
Randomize
RNumber = Int(Rnd*499) +1
While Not objRec.EOF
If objRec("ID") = RNumber THEN
... 這里是執行腳本 ...
end if
objRec.MoveNext
Wend
這很容易理解。首先,你取出1到500范圍之內的一個隨機數(假設500就是資料庫內記錄的總數)。然後,你遍歷每一記錄來測試ID 的值、檢查其是否匹配RNumber。滿足條件的話就執行由THEN 關鍵字開始的那一塊代碼。假如你的RNumber 等於495,那麼要循環一遍資料庫花的時間可就長了。雖然500這個數字看起來大了些,但相比更為穩固的企業解決方案這還是個小型資料庫了,後者通常在一個資料庫內就包含了成千上萬條記錄。這時候不就死定了?
採用SQL,你就可以很快地找出准確的記錄並且打開一個只包含該記錄的recordset,如下所示:
Randomize
RNumber = Int(Rnd*499) + 1
SQL = "SELECT * FROM Customers WHERE ID = " & RNumber
set objRec = ObjConn.Execute(SQL)
Response.WriteRNumber & " = " & objRec("ID") & " " & objRec("c_email")
不必寫出RNumber 和ID,你只需要檢查匹配情況即可。只要你對以上代碼的工作滿意,你自可按需操作「隨機」記錄。Recordset沒有包含其他內容,因此你很快就能找到你需要的記錄這樣就大大降低了處理時間。
再談隨機數
現在你下定決心要榨乾Random 函數的最後一滴油,那麼你可能會一次取出多條隨機記錄或者想採用一定隨機范圍內的記錄。把上面的標准Random 示例擴展一下就可以用SQL應對上面兩種情況了。
為了取出幾條隨機選擇的記錄並存放在同一recordset內,你可以存儲三個隨機數,然後查詢資料庫獲得匹配這些數字的記錄:
SQL = "SELECT * FROM Customers WHERE ID = " & RNumber & " OR ID = " & RNumber2 & " OR ID = " & RNumber3
假如你想選出10條記錄(也許是每次頁面裝載時的10條鏈接的列表),你可以用BETWEEN 或者數學等式選出第一條記錄和適當數量的遞增記錄。這一操作可以通過好幾種方式來完成,但是 SELECT 語句只顯示一種可能(這里的ID 是自動生成的號碼):
SQL = "SELECT * FROM Customers WHERE ID BETWEEN " & RNumber & " AND " & RNumber & "+ 9"
注意:以上代碼的執行目的不是檢查資料庫內是否有9條並發記錄。
隨機讀取若干條記錄,測試過
Access語法:SELECT top 10 * From 表名 ORDER BY Rnd(id)
Sql server:select top n * from 表名 order by newid()
mysql select * From 表名 Order By rand() Limit n
Access左連接語法(最近開發要用左連接,Access幫助什麼都沒有,網上沒有Access的SQL說明,只有自己測試, 現在記下以備後查)
語法 select table1.fd1,table1,fd2,table2.fd2 From table1 left join table2 on table1.fd1,table2.fd1 where ...
使用SQL語句 用...代替過長的字元串顯示
語法:
SQL資料庫:select case when len(field)>10 then left(field,10)+'...' else field end as news_name,news_id from tablename
Access資料庫:SELECT iif(len(field)>2,left(field,2)+'...',field) FROM tablename;
Conn.Execute說明
Execute方法
該方法用於執行SQL語句。根據SQL語句執行後是否返回記錄集,該方法的使用格式分為以下兩種:
1.執行SQL查詢語句時,將返回查詢得到的記錄集。用法為:
Set 對象變數名=連接對象.Execute("SQL 查詢語言")
Execute方法調用後,會自動創建記錄集對象,並將查詢結果存儲在該記錄對象中,通過Set方法,將記錄集賦給指定的對象保存,以後對象變數就代表了該記錄集對象。
2.執行SQL的操作性語言時,沒有記錄集的返回。此時用法為:
連接對象.Execute "SQL 操作性語句" [, RecordAffected][, Option]
·RecordAffected 為可選項,此出可放置一個變數,SQL語句執行後,所生效的記錄數會自動保存到該變數中。通過訪問該變數,就可知道SQL語句隊多少條記錄進行了操作。
·Option 可選項,該參數的取值通常為adCMDText,它用於告訴ADO,應該將Execute方法之後的第一個字元解釋為命令文本。通過指定該參數,可使執行更高效。
·BeginTrans、RollbackTrans、CommitTrans方法
這三個方法是連接對象提供的用於事務處理的方法。BeginTrans用於開始一個事物;RollbackTrans用於回滾事務;CommitTrans用於提交所有的事務處理結果,即確認事務的處理。
事務處理可以將一組操作視為一個整體,只有全部語句都成功執行後,事務處理才算成功;若其中有一個語句執行失敗,則整個處理就算失敗,並恢復到處里前的狀態。
BeginTrans和CommitTrans用於標記事務的開始和結束,在這兩個之間的語句,就是作為事務處理的語句。判斷事務處理是否成功,可通過連接對象的Error集合來實現,若Error集合的成員個數不為0,則說明有錯誤發生,事務處理失敗。Error集合中的每一個Error對象,代表一個錯誤信息。
SQL語句大全精要
2006/10/26 13:46
DELETE語句
DELETE語句:用於創建一個刪除查詢,可從列在 FROM 子句之中的一個或多個表中刪除記錄,且該子句滿足 WHERE 子句中的條件,可以使用DELETE刪除多個記錄。
語法:DELETE [table.*] FROM table WHERE criteria
語法:DELETE * FROM table WHERE criteria='查詢的字'
說明:table參數用於指定從其中刪除記錄的表的名稱。
criteria參數為一個表達式,用於指定哪些記錄應該被刪除的表達式。
可以使用 Execute 方法與一個 DROP 語句從資料庫中放棄整個表。不過,若用這種方法刪除表,將會失去表的結構。不同的是當使用 DELETE,只有數據會被刪除;表的結構以及表的所有屬性仍然保留,例如欄位屬性及索引。
UPDATE
有關UPDATE,急!!!!!!!!!!!
在ORACLE資料庫中
表 A ( ID ,FIRSTNAME,LASTNAME )
表 B( ID,LASTNAME)
表 A 中原來ID,FIRSTNAME兩個欄位的數據是完整的
表 B中原來ID,LASTNAME兩個欄位的數據是完整的
現在要把表 B中的LASTNAME欄位的相應的數據填入到A表中LASTNAME相應的位置。兩個表中的ID欄位是相互關聯的。
先謝謝了!!!!
update a set a.lastname=(select b.lastname from b where a.id=b.id)
掌握SQL四條最基本的數據操作語句:Insert,Select,Update和Delete。
練掌握SQL是資料庫用戶的寶貴財 富。在本文中,我們將引導你掌握四條最基本的數據操作語句—SQL的核心功能—來依次介紹比較操作符、選擇斷言以及三值邏輯。當你完成這些學習後,顯然你已經開始算是精通SQL了。
在我們開始之前,先使用CREATE TABLE語句來創建一個表(如圖1所示)。DDL語句對資料庫對象如表、列和視進行定義。它們並不對表中的行進行處理,這是因為DDL語句並不處理資料庫中實際的數據。這些工作由另一類SQL語句—數據操作語言(DML)語句進行處理。
SQL中有四種基本的DML操作:INSERT,SELECT,UPDATE和DELETE。由於這是大多數SQL用戶經常用到的,我們有必要在此對它們進行一一說明。在圖1中我們給出了一個名為EMPLOYEES的表。其中的每一行對應一個特定的雇員記錄。請熟悉這張表,我們在後面的例子中將要用到它。
⑧ SQL Server 過程語句精簡GROUP BY+while
deletefromJHOA_System_Temp_Call
whereSysTC_IDIN
(selecta.SysTC_IDfromJHOA_System_Temp_Callainnerjoin
(selectReg_Code,max(SysTC_Time)asSysTC_Time
fromJHOA_System_Temp_CallgroupbyReg_Codehavingcount(*)>50)t
ona.Reg_Code=t.Reg_Codeanda.SysTC_Time<>t.SysTC_Time)
--你試試思路:按Reg_Code分組只保留最近的時間