發表文章

目前顯示的是有「database」標籤的文章

如何使用FreeTDS的TDSDUMP功能debug

有人遇到一個問題,說他的PHP程式連資料庫(MSSQL 2008R2)查詢資料時會因為 Changed database context to 'DATABASE-NAME' 的錯誤而無法執行… "Changed database context to XXXX"這訊息的含意是…登入資料庫所用的帳號,做了切換資料庫的動作。如果登入資料庫的帳號有設定預設使用的資料庫,而程式運作中切換了資料庫。舉例,登入資料庫的帳號預設的資料庫為 DB-A,但程式登入資料庫後切換到 DB-B時,此時資料庫就會回傳這訊息。 雖然這樣的訊息不是『錯誤』,只能算是『資訊』…以往總覺得納悶這為何是錯誤?但,在這次追查問題中使用 SQL Server Profiler 時,發現到真的歸類於error... 總之,個人認為他的程式不可能是因為這的訊息樣而無法運作。且,他PHP程式所在的主機,都已經將錯誤等級設定為超過11才顯示,如下…

codeigniter與MySQL server has gone away

最近在做一個處理,於CLI下程式會下指令給splunk撈取資料,並等候splunk回覆結果。最後再將結果寫入資料庫。當查詢大量的資料時,等待splunk的時間會變長。 原本程式運作很正常,但在我重構程式調整操作DB的方式,以符合線上環境使用後,看log卻發現有時居然會出現了以下的錯誤… A Database Error Occurred Error Number: 2006 MySQL server has gone away 查了一下mysql官方文件,相關資料如下… http://dev.mysql.com/doc/refman/5.0/en/gone-away.html http://dev.mysql.com/doc/refman/5.0/en/error-messages-client.html#error_cr_server_gone_error 看了說明,我遇到的狀況和time out比較相同。和DBA討論、測試後…果然沒錯…就把問題給解決了~ 先說明我做了什麼修改,導致遇到此狀況?

PHP的query timeout對於lock中的tbale是否有效

之前有介紹過 如何設定 sybase 的 lock timeout ,將FreeTDS更新到0.91後,順便測試當資料庫發生鎖定時,query timeout是否能夠強制程式中斷,程式不會因此卡住?依舊同時測試MS SQL、及Sybase。 測試的假設狀況為…刻意將測試用table產生lock,同時以php程式去查詢已經被lock的table,該主機上使用FreeTDS 0.91,並且設定了query timeout為五秒(請參考 php存取mssql、sybase時,如何設定query timeout )。 測試的結果…FreeTDS果然對於這兩家資料庫的處理不同… MS SQL:查詢超過五秒後,查詢被中斷,控制權回到程式(不需設定lock timeout) Sybase:查詢超過五秒後,程式依舊卡住。(除非將lock的table解除lock,或設定lock timeout。控制權才會回到程式) 當然, FreeTDS 對於MS SQL的處理行為,是比較符合預期的… 在測試過程中,無意間發現一個現象…

php存取mssql、sybase時,如何設定query timeout

以前在整理 php.ini 、及 freetds.conf 的設定時,注意到兩者都有支援(query)timeout、及connect timeout,當時也作了設定。但最近的一些狀況,讓我好奇(query)timeout設定是否真的有發揮效果? 由於 FreeTDS 可以支援MS SQL、Sybase(FreeTDS is a set of libraries for Unix and Linux that allows your programs to natively talk to Microsoft SQL Server and Sybase databases.),所以就一併測試這兩種資料庫。首先,看一下相關設定的說明,php.ini 中對於MS SQL、Sybase的設定、及freetds的設定,分別如下… MS SQL Server configuration options ,提到mssql.timeout、mssql.connect_timeout這兩個參數 Sybase configuration options ,提到sybct.login_timeout、sybct.timeout這兩個參數 freetds.conf ,則提到(query)timeout、及connect timeout這兩個參數 測試的結果,無論是MS SQL、Sybase的timeout居然都沒效果。 難道又是文件和實際不符合嘛?找了些資料,看到 Bug #34647 mssql.timeout has no affect 中的討論、說明後,去挖出freetds change log,終於有點眉目。原來是因為我所使用的FreeTDS版本太舊,timeout機制在FreeTDS v8.2( freetds v0.82 change log )才開始支援。

如何設定 sybase 的 lock time out

最近處理的案子有點複雜,當中遇到一個狀況,在思考了很多解決方案後,最後決定把timeout機制放在資料庫上。 簡單的說,當啟動transaction後,為了避免transaction內的table因lock,導致程式無法正常反應。所以需要一個timeout機制。 基於MS SQL的經驗,記憶中可以設定lock time out時間。不過,此次配合的資料庫為Sybase,於是查了一下官方的文件…看到有三種作法 wait/nowaitoption of the lock tablecommand session-level lock-wait limit server-wide lock-wait limit 以我的案例,session-level lock-wait limit是三者中比較好的選擇。指令如下… set  lock {wait no_of_seconds | nowait}   應用方式如下…

CodeIgniter的Connecting to Multiple Databases,是否會造成大量連線數?

最近有人問了一個關於 CodeIgniter 的資料庫連線問題。問題是,當一個controller執行時,可能呼叫多的model。如果這些model在開資料庫連線時,全都採用"Connecting to Multiple Databases"的方式,豈不是一個網頁就會產生多個資料庫連線? CI採用singleton pattern。但"Connecting to Multiple Databases"的模式,卻是return instance。所以,這個疑問是有可能發生的。於是測試了一下… 做了一個小實驗。寫一個controller,他會呼叫三個不同的model。這三個model都採用"Connecting to Multiple Databases"方式,都連到同一台資料庫。如此,該資料庫上是不是就會有三個連線? 用var_dump()看每個連線,果然每個連線的resoure id都不同(共三個)。但直接在資料庫上看連線數,卻只有一個。這樣的結果蠻奇怪的。想了一下,原來是和php開啟資料庫處理方式有關。 我這次測試,使用兩種資料庫-Sybase、MSSql。兩者的狀況分別如下…

php連Oracle中文亂碼問題

最近使用php操作Oracle,遇到中文亂碼問題。最後在大家集思廣益下,把問題解決了,做個紀錄… 原以為使用php去連Oracle,應該和其他資料庫一樣,在連線時,設定正確的字元集(character_set)。再將轉碼過的中文寫入資料庫即可。沒想到,Oracle有點不同… php如何設定Oracle?在官方資料 - Configuring PHP with OCI8 ,於Setting the Oracle Environment這章節中提到需要設定環境變數(Common Oracle Environment Variables),如下… ORACLE_HOME ORACLE_SID LD_LIBRARY_PATH NLS_LANG ORA_SDTZ TNS_ADMIN 經過測試後,我們遇到中文亂碼的問題,只需要設定ORACLE_HOME、NLS_LAN即可。 當然,下述參數的設定值,需視機器環境作調整。

php5撈取sybase資料庫,欄位資料型態decimal時的問題

最近有人提出一個狀況,他在php5中去撈資料庫(資料庫為 sybase)中的數字,會有問題。舉例來說,資料庫存放的內容為 71.10 ,但經由php5所寫的程式,去取得出來的數值卻是71.09999999999999。妙的是…一樣的程式放到php4的環境去執行,卻是正常的,取得71.1。 原以為他所撈取欄位的資料型態為float,才導致這狀況。但瞭解狀況後,發現該欄位的資料型態為decimal (5,2)。也就是說不應該會有這樣的情況! php5連sybase,已經改用sybase_ct。因此,一開始認為這樣的問題,應該是sybase_ct本身的bug。其實,在sybase_ct的bug資料中也有提到這樣的狀況 - BUG #29064 。不過,該問題卻是已經解決… 在後續的問題釐清中,也發現原以為sybase_ct是個獨立的extension,和之前的freetds無關。事實上,sybase_ct還是需要freetds。另外,sybase_ct會吃freetds的設定。也就是會吃freetds設定檔(freetds.conf)中[global]的設定值。 換句話說,當我們使用如下的php程式去開啟sybase連線時,sybase_ct會去吃freetds設定檔(freetds.conf)中[global]內的設定值。 $conn = sybase_connect('123.123.123.123:5000','id','pwd','big5','test_php'); 然而,在freetds的設定檔(freetds.conf),預設中會有下列設定 [global] # TDS protocol version tds version = 4.2 這個tds版本代號有其含意,詳細可參考 Choosing a TDS protocol version 內的說明,視自己所用的資料庫採用不同的設定值。 居於上述兩點,解法就很簡單了。因為他是採用sybase,因此可以將此預設版本設定為5.0。問題就解決了。 [global] # TDS protocol version tds version = 5.0 參考資料 TDS版本說明 freetds ...

在trigger中利用@@rowcount

最近在對於系統作些調整、修改。其間,為了資料的一致性,最後還是決定採用觸發(trigger) 。為了照顧好資料庫(的效能),於是在思考如何減少trigger內不必要的語法執行(也就是沒資料被異動時,就算trigge被呼叫起來也不需要作任何動作) 翻了一下手上的工具書- Inside Microsoft SQL Server 2005:T-SQL PROGRAMMING 中文版 。在這本書(個人覺得這本書非常充實,欲瞭解MS SQL 2005、新功能、調教資料庫與進階應用等,建議可以看看本書)中提到一個作法,利用@@rowcount來協助判斷。 也就是在trigger一開始,就直接利用@@rowcount來判斷使否有資料被異動(以我的案例,我是要針對是否有資料真的被刪除,才去作一些處理)。有資料被異動,也就是@@rowcount傳回大於0的值,方才執行後續的SQL語法。否則就直接跳出,避免多作任何SQL語法,造成無用的資源浪費。 不過,一開始嘗試時卻是失敗的… 後來才注意到,因為我是利用SQL 2005 Studio 產生的trigger範例語法,因此他內建會放入SET NOCOUNT ON; ,這會導致@@rowcount不傳回值。 可是,在 MS SQL官方文件 中明明提及 - 即使 SET NOCOUNT 是 ON,也會更新 @@ROWCOUNT 函數。但…trigger中使用@@rowcount,就是會被影響! 以下,就是最基本的處理範例 CREATE TRIGGER [dbo].[tri_test] ON [dbo].[table_test] AFTER DELETE AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. --SET NOCOUNT ON; --以上三行語法為 SQL 2005 內建會產生的 IF @@rowcount=0 BEGIN --直接離開 RETURN ; END ELSE BEGIN ...

在MS sql server 2005中,如何將預存程序(store procedure)的結果insert到table?

由於種種原因,有個需求 -- 要將預存程序(store procedure)的查詢結果,直接insert到table ,然後再由該table去取得資料! 一開始最直接的想法,就是利用 SELECT INTO 的方式,所以採用下述語法(以sp_who為範例,產生資料) SELECT * INTO #temptale FROM (EXEC sp_who) 結果…天不從人願,sql server似乎不會將sp_who的結果當作一個table。後來改用配合 with 依舊也沒辦法… 忽然想到之前看到別人SQL資料隱碼攻擊(sql injection)的語法,覺得該語法應該可以在此利用,所以將原本的語法修改如下… SELECT * INTO #temptale FROM OPENROWSET( 'SQLNCLI', 'Server=localhost;Trusted_Connection=yes;','sp_who') 果然,就可以將預存程序(store procedure)的結果直接塞入table,讓我後續利用了! 附註: 以上指令其實是需要有適當的權限配合,方可執行! 但很奇怪的是…我執行sp_who沒問題,但改以sp_who2卻會有錯誤!應該不會是因為sp_who2為非正式預存程序(store procedure)吧? :)

微軟針對ASP提供SQL Injection分析工具(Microsoft ® Source Code Analyzer for SQL Injection)

資料隱碼(sql injection)攻擊玩法越來越多變,因此市場上也開始有相關資安工具出現,提供掃瞄系統程式是否有防堵這部分。有的是針對線上運作中的網頁掃瞄,有的是針對靜態的程式去掃瞄…不過,一直沒看到Microsoft有針對這部分提供工具(相關資訊倒是提供不少,但大都只針對他們主推的 .Net來說明。雖然說觀念相同,但比較難見到針對以前ASP這部分的) 不知是不是五月底那一波大規模的資料隱碼(sql injection)攻擊,所以台灣微軟有出些 專文 出來…不過,引起我注意的,卻是在差不多時間出現的這套工具 - Microsoft R Source Code Analyzer for SQL Injection 該工具是並非針對線上程式做侵入式的掃瞄(雖然有些免費的工具或網站,可以提供線上去掃瞄網頁。不過,總覺得有點引狼入室的感覺…),而是針對『靜態程式』去掃瞄。MS提供的參考資料還不少,有 中文介紹 ,也有 英文簡易介紹 (詳細英文介紹,建議一定要看解開壓縮後的readme.htm)! 一開始使用的時候,覺得還不錯,他會產生出一個xml的測試結果。但馬上也發現兩個缺點… 就是該工具只能針對單一檔案處理。 偏偏一般來講,我們要撿測自己的系統時,一定是一個目錄(甚至多個目錄)。這樣的處理方式,就稍嫌不便了… 做出來的xml,實在看不懂 拿了免費的XML Notepad 2007來看,實在還是很難解讀這分析結果…

TRANSACTION ISOLATION vs LOCK

話說SQL server有支援下列幾種隔離模式 READ UNCOMMITTED READ COMMITTED REPEATABLE READ SNAPSHOT(2005新增) SERIALIZABLE 當中READ COMMITTED為內定所採用的模式。內定採用這樣的模式是好?是壞?見仁見智吧~不過,有時還真的是需要READ UNCOMMITTED模式。所以做個測試,著手把connection的模式修改為READ UNCOMMITTED模式… 在ASP中的作法如下… db.IsolationLevel = adXactReadUncommitted 或者 db.IsolationLevel = 256 修改好後,跑個ASP來測試,卻發結果並非我所想像,依舊因為LOCK問題,導致程式卡在那兒~ (我在 SQL Server Management Studio Express上直接下 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ,結果卻是我所預期--不會受到 lock影響,依舊可以抓到資料) select * from [test_table] 於是,只好到google上找找資料,看看為何設定後卻無效果~說法千奇百怪…結果,還是在 MS官方資料 上看到一句很關鍵的話,照者測試的結果,果真有效… 程式修改如下 db.BeginTrans() select * from [test_table] db.RollBackTrans 不過,這樣感覺有點脫褲子放屁…看來,以後還是直接用下列方式就好了… select * from [test_table] WITH (NOLOCK)