re: 軟件開發#前途 久城 2007-09-15 18:44
我也在做外包,的確不需要很多的技術含量。相對技術來說,外包更多的是側重軟件工程各方面的能力,這需要經驗。
黑蝙蝠,好久不見你出沒了啊。
re: JAVA元數據注釋初探 久城 2007-09-15 11:20
JAVA元數據的應用挺有意思的,一直想學習一下,卻一直沒有好好學習過。
我見過的,只有Javadoc是元數據比較常見的應用了哈哈。
學習一下。謝謝樓主。
realsmy@gmail.com
很感興趣,不知道樓主能介紹下你的開發環境和工具嗎?~很想借鑒一下。
re: JAVA中的時間操作 久城 2007-09-12 08:00
關于時間的運算,用Calendar或者其子類GregorianCalendar也許更好一些。
re: 索引初步接觸 久城 2007-09-11 11:31
在網上查到的傳閱比較廣泛的一個實例,感覺對理解索引的應用有很大的幫助。
具體出處不詳。
如何讓你的SQL運行得更快
---- 人們在使用SQL時往往會陷入一個誤區,即太關注于所得的結果是否正確,而忽略了不同的實現方法之間可能存在的性能差異,這種性能差異在大型的或是復雜的數據庫環境中(如聯機事務處理OLTP或決策支持系統DSS)中表現得尤為明顯。筆者在工作實踐中發現,不良的SQL往往來自于不恰當的索引設計、不充份的連接條件和不可優化的where子句。在對它們進行適當的優化后,其運行速度有了明顯地提高!下面我將從這三個方面分別進行總結:
---- 為了更直觀地說明問題,所有實例中的SQL運行時間均經過測試,不超過1秒的均表示為(< 1秒)。
---- 測試環境--
---- 主機:HP LH II
---- 主頻:330MHZ
---- 內存:128兆
---- 操作系統:Operserver5.0.4
---- 數據庫:Sybase11.0.3
一、不合理的索引設計
----例:表record有620000行,試看在不同的索引下,下面幾個 SQL的運行情況:
---- 1.在date上建有一非個群集索引
select count(*) from record where date >
'19991201' and date < '19991214'and amount >
2000 (25秒)
select date,sum(amount) from record group by date
(55秒)
select count(*) from record where date >
'19990901' and place in ('BJ','SH') (27秒)
---- 分析:
----date上有大量的重復值,在非群集索引下,數據在物理上隨機存放在數據頁上,在范圍查找時,必須執行一次表掃描才能找到這一范圍內的全部行。
---- 2.在date上的一個群集索引
select count(*) from record where date >
'19991201' and date < '19991214' and amount >
2000 (14秒)
select date,sum(amount) from record group by date
(28秒)
select count(*) from record where date >
'19990901' and place in ('BJ','SH')(14秒)
---- 分析:
---- 在群集索引下,數據在物理上按順序在數據頁上,重復值也排列在一起,因而在范圍查找時,可以先找到這個范圍的起末點,且只在這個范圍內掃描數據頁,避免了大范 圍掃描,提高了查詢速度。
---- 3.在place,date,amount上的組合索引
select count(*) from record where date >
'19991201' and date < '19991214' and amount >
2000 (26秒)
select date,sum(amount) from record group by date
(27秒)
select count(*) from record where date >
'19990901' and place in ('BJ, 'SH')(< 1秒)
---- 分析:
---- 這是一個不很合理的組合索引,因為它的前導列是place,第一和第二條SQL沒有引用place,因此也沒有利用上索引;第三個SQL使用了place,且引用的所有列都包含在組合索引中,形成了索引覆蓋,所以它的速度是非常快的。
---- 4.在date,place,amount上的組合索引
select count(*) from record where date >
'19991201' and date < '19991214' and amount >
2000(< 1秒)
select date,sum(amount) from record group by date
(11秒)
select count(*) from record where date >
'19990901' and place in ('BJ','SH')(< 1秒)
---- 分析:
---- 這是一個合理的組合索引。它將date作為前導列,使每個SQL都可以利用索引,并且在第一和第三個SQL中形成了索引覆蓋,因而性能達到了最優。
---- 5.總結:
---- 缺省情況下建立的索引是非群集索引,但有時它并不是最佳的;合理的索引設計要建立在對各種查詢的分析和預測上。一般來說:
---- ①.有大量重復值、且經常有范圍查詢
(between, >,< ,>=,< =)和order by
、group by發生的列,可考慮建立群集索引;
---- ②.經常同時存取多列,且每列都含有重復值可考慮建立組合索引;
---- ③.組合索引要盡量使關鍵查詢形成索引覆蓋,其前導列一定是使用最頻繁的列。
二、不充份的連接條件:
---- 例:表card有7896行,在card_no上有一個非聚集索引,表account有191122行,在account_no上有一個非聚集索引,試看在不同的表連接條件下,兩個SQL的執行情況:
select sum(a.amount) from account a,
card b where a.card_no = b.card_no(20秒)
---- 將SQL改為:
select sum(a.amount) from account a,
card b where a.card_no = b.card_no and a.
account_no=b.account_no(< 1秒)
---- 分析:
---- 在第一個連接條件下,最佳查詢方案是將account作外層表,card作內層表,利用card上的索引,其I/O次數可由以下公式估算為:
---- 外層表account上的22541頁+(外層表account的191122行*內層表card上對應外層表第一行所要查找的3頁)=595907次I/O
---- 在第二個連接條件下,最佳查詢方案是將card作外層表,account作內層表,利用account上的索引,其I/O次數可由以下公式估算為:
---- 外層表card上的1944頁+(外層表card的7896行*內層表account上對應外層表每一行所要查找的4頁)= 33528次I/O
---- 可見,只有充份的連接條件,真正的最佳方案才會被執行。
---- 總結:
---- 1.多表操作在被實際執行前,查詢優化器會根據連接條件,列出幾組可能的連接方案并從中找出系統開銷最小的最佳方案。連接條件要充份考慮帶有索引的表、行數多的表;內外表的選擇可由公式:外層表中的匹配行數*內層表中每一次查找的次數確定,乘積最小為最佳方案。
---- 2.查看執行方案的方法-- 用set showplanon,打開showplan選項,就可以看到連接順序、使用何種索引的信息;想看更詳細的信息,需用sa角色執行dbcc(3604,310,302)。
三、不可優化的where子句
---- 1.例:下列SQL條件語句中的列都建有恰當的索引,但執行速度卻非常慢:
select * from record where
substring(card_no,1,4)='5378'(13秒)
select * from record where
amount/30< 1000(11秒)
select * from record where
convert(char(10),date,112)='19991201'(10秒)
---- 分析:
---- where子句中對列的任何操作結果都是在SQL運行時逐列計算得到的,因此它不得不進行表搜索,而沒有使用該列上面的索引;如果這些結果在查詢編譯時就能得到,那么就可以被SQL優化器優化,使用索引,避免表搜索,因此將SQL重寫成下面這樣:
select * from record where card_no like
'5378%'(< 1秒)
select * from record where amount
< 1000*30(< 1秒)
select * from record where date= '1999/12/01'
(< 1秒)
---- 你會發現SQL明顯快起來!
---- 2.例:表stuff有200000行,id_no上有非群集索引,請看下面這個SQL:
select count(*) from stuff where id_no in('0','1')
(23秒)
---- 分析:
---- where條件中的'in'在邏輯上相當于'or',所以語法分析器會將in ('0','1')轉化為id_no ='0' or id_no='1'來執行。我們期望它會根據每個or子句分別查找,再將結果相加,這樣可以利用id_no上的索引;但實際上(根據showplan),它卻采用了"OR策略",即先取出滿足每個or子句的行,存入臨時數據庫的工作表中,再建立唯一索引以去掉重復行,最后從這個臨時表中計算結果。因此,實際過程沒有利用id_no上索引,并且完成時間還要受tempdb數據庫性能的影響。
---- 實踐證明,表的行數越多,工作表的性能就越差,當stuff有620000行時,執行時間竟達到220秒!還不如將or子句分開:
select count(*) from stuff where id_no='0'
select count(*) from stuff where id_no='1'
---- 得到兩個結果,再作一次加法合算。因為每句都使用了索引,執行時間只有3秒,在620000行下,時間也只有4秒。或者,用更好的方法,寫一個簡單的存儲過程:
create proc count_stuff as
declare @a int
declare @b int
declare @c int
declare @d char(10)
begin
select @a=count(*) from stuff where id_no='0'
select @b=count(*) from stuff where id_no='1'
end
select @c=@a+@b
select @d=convert(char(10),@c)
print @d
---- 直接算出結果,執行時間同上面一樣快!
---- 總結:
---- 可見,所謂優化即where子句利用了索引,不可優化即發生了表掃描或額外開銷。
---- 1.任何對列的操作都將導致表掃描,它包括數據庫函數、計算表達式等等,查詢時要盡可能將操作移至等號右邊。
---- 2.in、or子句常會使用工作表,使索引失效;如果不產生大量重復值,可以考慮把子句拆開;拆開的子句中應該包含索引。
---- 3.要善于使用存儲過程,它使SQL變得更加靈活和高效。
---- 從以上這些例子可以看出,SQL優化的實質就是在結果正確的前提下,用優化器可以識別的語句,充份利用索引,減少表掃描的I/O次數,盡量避免表搜索的發生。其實SQL的性能優化是一個復雜的過程,上述這些只是在應用層次的一種體現,深入研究還會涉及數據庫層的資源配置、網絡層的流量控制以及操作系統層的總體設計。
1 邏輯數據庫和表的設計
數據庫的邏輯設計、包括表與表之間的關系是優化關系型數據庫性能的核心。一個好的邏輯數據庫設計可以為優化數據庫和應用程序打下良好的基礎。
標準化的數據庫邏輯設計包括用多的、有相互關系的窄表來代替很多列的長數據表。下面是一些使用標準化表的一些好處。
A:由于表窄,因此可以使排序和建立索引更為迅速
B:由于多表,所以多鏃的索引成為可能
C:更窄更緊湊的索引
D:每個表中可以有少一些的索引,因此可以提高insert update delete等的速度,因為這些操作在索引多的情況下會對系統性能產生很大的影響
E:更少的空值和更少的多余值,增加了數據庫的緊湊性由于標準化,所以會增加了在獲取數據時引用表的數目和其間的連接關系的復雜性。太多的表和復雜的連接關系會降低服務器的性能,因此在這兩者之間需要綜合考慮。
定義具有相關關系的主鍵和外來鍵時應該注意的事項主要是:用于連接多表的主鍵和參考的鍵要有相同的數據類型。
2 索引的設計
A:盡量避免表掃描
檢查你的查詢語句的where子句,因為這是優化器重要關注的地方。包含在where里面的每一列(column)都是可能的侯選索引,為能達到最優的性能,考慮在下面給出的例子:對于在where子句中給出了column1這個列。
下面的兩個條件可以提高索引的優化查詢性能!
第一:在表中的column1列上有一個單索引
第二:在表中有多索引,但是column1是第一個索引的列
避免定義多索引而column1是第二個或后面的索引,這樣的索引不能優化服務器性能
例如:下面的例子用了pubs數據庫。
SELECT au_id, au_lname, au_fname FROM authors
WHERE au_lname = ’White’
按下面幾個列上建立的索引將會是對優化器有用的索引
?au_lname
?au_lname, au_fname
而在下面幾個列上建立的索引將不會對優化器起到好的作用
?au_address
?au_fname, au_lname
考慮使用窄的索引在一個或兩個列上,窄索引比多索引和復合索引更能有效。用窄的索引,在每一頁上將會有更多的行和更少的索引級別(相對與多索引和復合索引而言),這將推進系統性能。
對于多列索引,SQL Server維持一個在所有列的索引上的密度統計(用于聯合)和在第一個索引上的histogram(柱狀圖)統計。根據統計結果,如果在復合索引上的第一個索引很少被選擇使用,那么優化器對很多查詢請求將不會使用索引。
有用的索引會提高select語句的性能,包括insert,uodate,delete。
但是,由于改變一個表的內容,將會影響索引。每一個insert,update,delete語句將會使性能下降一些。實驗表明,不要在一個單表上用大量的索引,不要在共享的列上(指在多表中用了參考約束)使用重疊的索引。
在某一列上檢查唯一的數據的個數,比較它與表中數據的行數做一個比較。這就是數據的選擇性,這比較結果將會幫助你決定是否將某一列作為侯選的索引列,如果需要,建哪一種索引。你可以用下面的查詢語句返回某一列的不同值的數目。
select count(distinct cloumn_name) from table_name
假設column_name是一個10000行的表,則看column_name返回值來決定是否應該使用,及應該使用什么索引。
Unique values Index
5000 Nonclustered index
20 Clustered index
3 No index
鏃索引和非鏃索引的選擇
<1:>鏃索引是行的物理順序和索引的順序是一致的。頁級,低層等索引的各個級別上都包含實際的數據頁。一個表只能是有一個鏃索引。由于update,delete語句要求相對多一些的讀操作,因此鏃索引常常能加速這樣的操作。在至少有一個索引的表中,你應該有一個鏃索引。
在下面的幾個情況下,你可以考慮用鏃索引:
例如: 某列包括的不同值的個數是有限的(但是不是極少的)
顧客表的州名列有50個左右的不同州名的縮寫值,可以使用鏃索引。
例如: 對返回一定范圍內值的列可以使用鏃索引,比如用between,>,>=,<,<=等等來對列進行操作的列上。
select * from sales where ord_date between ’5/1/93’ and ’6/1/93’
例如: 對查詢時返回大量結果的列可以使用鏃索引。
SELECT * FROM phonebook WHERE last_name = ’Smith’
當有大量的行正在被插入表中時,要避免在本表一個自然增長(例如,identity列)的列上建立鏃索引。如果你建立了鏃的索引,那么insert的性能就會大大降低。因為每一個插入的行必須到表的最后,表的最后一個數據頁。
當一個數據正在被插入(這時這個數據頁是被鎖定的),所有的其他插入行必須等待直到當前的插入已經結束。
一個索引的葉級頁中包括實際的數據頁,并且在硬盤上的數據頁的次序是跟鏃索引的邏輯次序一樣的。
<2:>一個非鏃的索引就是行的物理次序與索引的次序是不同的。一個非鏃索引的葉級包含了指向行數據頁的指針。
在一個表中可以有多個非鏃索引,你可以在以下幾個情況下考慮使用非鏃索引。
在有很多不同值的列上可以考慮使用非鏃索引
例如:一個part_id列在一個part表中
select * from employee where emp_id = ’pcm9809f’
查詢語句中用order by 子句的列上可以考慮使用鏃索引
3 查詢語句的設計
SQL Server優化器通過分析查詢語句,自動對查詢進行優化并決定最有效的執行方案。優化器分析查詢語句來決定那個子句可以被優化,并針對可以被優化查詢的子句來選擇有用的索引。最后優化器比較所有可能的執行方案并選擇最有效的一個方案出來。
在執行一個查詢時,用一個where子句來限制必須處理的行數,除非完全需要,否則應該避免在一個表中無限制地讀并處理所有的行。
例如下面的例子,
select qty from sales where stor_id=7131
是很有效的比下面這個無限制的查詢
select qty from sales
避免給客戶的最后數據選擇返回大量的結果集。允許SQL Server運行滿足它目的的函數限制結果集的大小是更有效的。
這能減少網絡I/O并能提高多用戶的相關并發時的應用程序性能。因為優化器關注的焦點就是where子句的查詢,以利用有用的索引。在表中的每一個索引都可能成為包括在where子句中的侯選索引。為了最好的性能可以遵照下面的用于一個給定列column1的索引。
第一:在表中的column1列上有一個單索引
第二:在表中有多索引,但是column1是第一個索引的列不要在where子句中使用沒有column1列索引的查詢語句,并避免在where子句用一個多索引的非第一個索引的索引。
這時多索引是沒有用的。
For example, given a multicolumn index on the au_lname, au_fname columns of the authors table in
the pubs database,
下面這個query語句利用了au_lname上的索引
SELECT au_id, au_lname, au_fname FROM authors
WHERE au_lname = ’White’
AND au_fname = ’Johnson’
SELECT au_id, au_lname, au_fname FROM authors
WHERE au_lname = ’White’
下面這個查詢沒有利用索引,因為他使用了多索引的非第一個索引的索引
SELECT au_id, au_lname, au_fname FROM authors
WHERE au_fname = ’Johnson’
網站中,一般什么樣的數據放在XML文件中,而不是放到應用數據庫中?為什么?放到XML中,一般都是結合什么樣的技術去應用?
看了兩個帖子,正好是我現在想研究的內容,忍不住問了兩個即比較低級的問題,還請見諒。:)
re: 貼一個生成靜態HTML用的工具類 久城 2007-09-10 14:58
問一個比較低級的問題,網站中的很多動態增加的HTML頁面就是這樣作成的嗎?
比如csdn上每天的一些動態新聞的網頁,都是一個HTML頁面,目錄結構可能是www.csdn.net/news/20070910/0001.html,這樣的頁面都是如何生成的?是不是也是用一個專門生成HTML頁面的類來自動生成啊?
迷惑中,還請指教。
re: 我的blog訪問者分析 久城 2007-08-31 10:40
哈哈,太有想法了啊。
剛剛試了下,挺有意思。GOOGLE就是牛啊。
re: 我的blog訪問者分析 久城 2007-08-31 10:27
-.-!.........博主........就是草兒你啊。....
現在只有顯示結果,如果BZ能再談談對這一結果的看法就好了。:)
re: 新功能發布 久城 2007-08-31 08:42
維護簽名頁面中的編輯器中的‘維護簽名’按鈕,是不是可以去掉了?
用JS實現的?我JS盲。看起來挺有意思。
也可以寫成一個批處理文件。
native2ascii a.properties b.properties
re: 轉 侯捷談Java反射機制 久城 2007-08-29 14:30
小小UP下。
五個月前,做JAVA CLASS LOADING的畢設,看過這篇文章,當時很費解侯老先生到底在研究什么。
今天,想嘗試研究一下JAVA類的序列化,又看了一遍這篇文章,收益良多。
2007年8月11日,在屋睡了一天的覺。
2007年8月12日,沈陽下了一天的雨。
re: 基于TCP的多人聊天小程序 久城 2007-05-25 13:08
@L
:)工作的人和沒工作的人考慮的事情就是不一樣啊!我只考慮了實現通信,卻沒有想過程序的性能如何。好多想法還太單純。
..恩,要看的東西還有好多。謝謝指點。
re: 基于TCP的多人聊天小程序 久城 2007-05-25 09:39
原來如此。我昨天用Applet嘗試了半天,始終連接不上服務端。一直不知道是哪里出錯了。呵呵。
我的理想也是從事教育...因為賺錢...為什么賺錢呢?
呵呵,事實擺在眼前,其實大家人人都心知肚明。
re: java元數據的學習 久城 2007-05-22 16:40
看完了,試了下。終于有了些思路。謝謝BZ。
只是有些疑惑,我們什么時候能用到annotation呢?
@劉甘泉
多謝指教。在網上看到一些文章也是提醒要注意修改時的操作。
至于修改什么還不是很清楚。
我想,在應用深度clone的時候,需要重寫Object類中的clone方法,對于基本類型就不用考慮了,對于非基本類型,需要手動的進行“復制”。大家所說的“會引起問題”是出自這里吧?這個“復制”如果也是一個clone,就需要考慮這個非基本類型對象是否允許被clone,這個clone操作是否也是深度clone等問題。
象StringBuffer這樣的,不可修改的類。就需要手動的“COPY IT!”
還有一些就需要用到迭代方法,來迭代執行clone方法,達到N深度clone的效果。
這些我還沒有深入的研究。感覺實踐中用的機會很少。
@網路冷眼@BlogJava
哦!多謝指教。還真沒注意這個地方。一直以為是Group of Four呢!一叫“四人幫”總是讓我想起中國的那四個人...