デットロックが発生原因について、もうひとつ付け加えたい。
■現象
2つのセッションがあり、1つのテーブルがあるとする。
①あるセッションは、テーブルにINSERTを実行
②あるセッションは、条件指定でSELECTを実行
ここで、デットロックが発生したとする。
①と②は、まったく条件が異なるため、デットロックしないはずでは。。
■原因
テーブルには、INDEXが設定されており、INSERTが
COMMITされるまでは、その
INDEX
を利用したSELECTがロック待ちになる。
(INDEXの木構造を再構築中のためではないか)
■対策
INDEXを参照しないでSELECTする。
利用頻度が低い
INDEX
は、削除した方が、INSERTも早くなる。
INDEXは、パフォーマンスを大幅に改善することがあるが、
デットロックを引き起こす原因になることも忘れてはならない。
2012年12月9日日曜日
SQLSERVER NOLOCKオプションの有効性
今回は、NOLOCKオプションについて、いくつか書いてみたいと思う。
■効果
あるテーブルがUPDATEされ、COMMIT待ちの状態であるが、
NOLOCKオプションをつけると、COMMIT前のデータがSELECTできてしまう。
つまり、複数のセッションで処理する場合、待ち時間がなくなるため
パフォーマンスアップにつながるわけである。
■弊害
COMMIT前のデータが読めるというのは、ダーティリードとも呼ばれる。
何が問題かというと、ROLLBACKされたときに、読み取ったデータが
存在しなくなるということである。または存在しても異なっている場合がある。
取得した値を利用して、処理をしてみたが、あるタイミングで、その値は
無効なものとなっている。前提が崩れているとすれば処理結果も信用できない。
また、NOLOCKオプションを付ける前だと、ロック待ちとして排他されていたが
付けた後だと、同時実行されるようになり、整合性に問題がでる場合がある。
■使用場所
①別記「SQLSERVER デットロックを防ぐ」にあるように、デットロック回避に使う。
→NOLOCKオプションでSELECT後、一意キーでアクセスすることにより、
ロック範囲を狭めるのと、整合性の確認、パフォーマンスアップにつながる。
②ROLLBACKがほぼなく、パフォーマンスアップしたい箇所につかう。
または、ROLLBACKされても整合性に問題が起きない箇所。
在庫データの参照など、ダーティリード時の影響が大きい箇所などには適用せず
リスクが比較的少ない箇所から実験するのもひとつの手である。
■効果
あるテーブルがUPDATEされ、COMMIT待ちの状態であるが、
NOLOCKオプションをつけると、COMMIT前のデータがSELECTできてしまう。
つまり、複数のセッションで処理する場合、待ち時間がなくなるため
パフォーマンスアップにつながるわけである。
■弊害
COMMIT前のデータが読めるというのは、ダーティリードとも呼ばれる。
何が問題かというと、ROLLBACKされたときに、読み取ったデータが
存在しなくなるということである。または存在しても異なっている場合がある。
取得した値を利用して、処理をしてみたが、あるタイミングで、その値は
無効なものとなっている。前提が崩れているとすれば処理結果も信用できない。
また、NOLOCKオプションを付ける前だと、ロック待ちとして排他されていたが
付けた後だと、同時実行されるようになり、整合性に問題がでる場合がある。
■使用場所
①別記「SQLSERVER デットロックを防ぐ」にあるように、デットロック回避に使う。
→NOLOCKオプションでSELECT後、一意キーでアクセスすることにより、
ロック範囲を狭めるのと、整合性の確認、パフォーマンスアップにつながる。
②ROLLBACKがほぼなく、パフォーマンスアップしたい箇所につかう。
または、ROLLBACKされても整合性に問題が起きない箇所。
在庫データの参照など、ダーティリード時の影響が大きい箇所などには適用せず
リスクが比較的少ない箇所から実験するのもひとつの手である。
SQLSERVER デットロックを防ぐ
2つのセッションが1つのテーブルにアクセスするとき、異なる抽出条件に
なっているにも関わらず、そこでデットロックが発生することはないだろうか?
■状況
たとえば、テーブルのカラムが
ID
GROUP
NAME
AGE
となっていて、
セッション①
WHERE ID = 1
セッション②
WHERE ID = 2
などとアクセスする。
このとき、別のデータを取得しようとしているので、ぶつからないはずである。
■原因
いくつかあるのだが、以下のような場合である。
①ID、GROUPのカラムで複合一意キーを指定していたが、どちらか片方で
アクセスしていた。
②一意キー以外の条件でアクセスすると、関係ないレコードまでロックされる
(SQLSERVERは、勝手に広範囲をロックしてしまうようだ)
■対応策
①複合一意キーの場合は、その定義順序で、定義されているカラムを必ず指定すること
② 一意キー以外の条件でアクセスする場合、WITH (NOLOCK) オプションでまず
データを取得する。その後、取得結果をカーソルでまわしながら、一意キーで
再度SELECTする。
※ WITH (NOLOCK) オプションは、ROLLBACK時の影響があることから乱用は避けたい
このような対応で、ロック範囲は意図した通りとなり、デットロックは軽減される。
■参考
ロック範囲が意図した範囲か確認する方法として、以下がある。
「Management Studio」を2つ起動させておく。
①片方で、範囲外と思われるレコードをUPDATE
②もう片方で、確認したいSELECT文を流す( 調べたいWHERE句を指定して )
以上を実行してみて、固まる(ロック待ち)となれば、ぶつかっているし、
無事にSELECTできれば、ロック範囲は重なっていない。
なっているにも関わらず、そこでデットロックが発生することはないだろうか?
■状況
たとえば、テーブルのカラムが
ID
GROUP
NAME
AGE
となっていて、
セッション①
WHERE ID = 1
セッション②
WHERE ID = 2
などとアクセスする。
このとき、別のデータを取得しようとしているので、ぶつからないはずである。
■原因
いくつかあるのだが、以下のような場合である。
①ID、GROUPのカラムで複合一意キーを指定していたが、どちらか片方で
アクセスしていた。
②一意キー以外の条件でアクセスすると、関係ないレコードまでロックされる
(SQLSERVERは、勝手に広範囲をロックしてしまうようだ)
■対応策
①複合一意キーの場合は、その定義順序で、定義されているカラムを必ず指定すること
② 一意キー以外の条件でアクセスする場合、WITH (NOLOCK) オプションでまず
データを取得する。その後、取得結果をカーソルでまわしながら、一意キーで
再度SELECTする。
※ WITH (NOLOCK) オプションは、ROLLBACK時の影響があることから乱用は避けたい
このような対応で、ロック範囲は意図した通りとなり、デットロックは軽減される。
■参考
ロック範囲が意図した範囲か確認する方法として、以下がある。
「Management Studio」を2つ起動させておく。
①片方で、範囲外と思われるレコードをUPDATE
②もう片方で、確認したいSELECT文を流す( 調べたいWHERE句を指定して )
以上を実行してみて、固まる(ロック待ち)となれば、ぶつかっているし、
無事にSELECTできれば、ロック範囲は重なっていない。
2012年8月22日水曜日
SQLSERVER 3414 エラー
昨日まで使えたのに今日立ち上げたらつながらなくなった
ということはないだろうか?
Management Studioでデータベースを開こうとすると以下のエラー出る
・エラー 3414、Error: 3414 ( MSSQLSERVER_3414 )
・データベースにアクセスできません。接続できない
・復元中にエラーが発生したので、データベース は再開されません
・利用できません、利用不可
・An error occurred during recovery, preventing the database
これは、データベース起動中にエラーが発生しオープンできずにいる状態で
Management Studioからどうすることもできないように見える。
が、しかし、そこはデータベースなので万が一のディスクエラーにもある程度
対処できるようコマンドが用意されているのだ。
■手順 (Resolution)
①ステータスリセット
exec master..sp_resetstatus データベース名
②データベースをリカバリ
DBCC DBRECOVER ('データベース名', IGNOREERRORS)
③復旧後の整合性チェック
DBCC CHECKDB ('データベース名') WITH NO_INFOMSGS, ALL_ERRORMSGS;
④ ③でエラーが出ず、データベースが開ければ無事完了である
■結果
このような事態が本番環境で発生するとサービスが停止してしまうので影響は甚大である。
普段から障害発生時を想定して、エラー原因と対処方法などを調べておいたり、
実際、テスト環境で発生したときにじっくり対処方法を検討し、まとめておくとよいだろう。
ということはないだろうか?
Management Studioでデータベースを開こうとすると以下のエラー出る
・エラー 3414、Error: 3414 ( MSSQLSERVER_3414 )
・データベースにアクセスできません。接続できない
・復元中にエラーが発生したので、データベース は再開されません
・利用できません、利用不可
・An error occurred during recovery, preventing the database
これは、データベース起動中にエラーが発生しオープンできずにいる状態で
Management Studioからどうすることもできないように見える。
が、しかし、そこはデータベースなので万が一のディスクエラーにもある程度
対処できるようコマンドが用意されているのだ。
■手順 (Resolution)
①ステータスリセット
exec master..sp_resetstatus データベース名
②データベースをリカバリ
DBCC DBRECOVER ('データベース名', IGNOREERRORS)
③復旧後の整合性チェック
DBCC CHECKDB ('データベース名') WITH NO_INFOMSGS, ALL_ERRORMSGS;
④ ③でエラーが出ず、データベースが開ければ無事完了である
■結果
このような事態が本番環境で発生するとサービスが停止してしまうので影響は甚大である。
普段から障害発生時を想定して、エラー原因と対処方法などを調べておいたり、
実際、テスト環境で発生したときにじっくり対処方法を検討し、まとめておくとよいだろう。
2012年3月31日土曜日
ORA-12516 エラーの原因・対処
■エラー内容
ORA-12516: TNS: リスナーは、一致するプロトコル・スタックが使用可能なハンドラを
検出できませんでした。
■原因
停電などでHUBの電源が落ちた際、クライアントPCとデータベースが一度にたくさん
切断される場合がある。このとき、データベース側には、これまで接続していた
プロセス・セッションが残っている。復旧後に、クライアントPCから接続されると
新たにプロセス・セッションがデータベースのメモリに割り当てされる。
つまり、サーバ上のメモリ使用量が倍近くに膨らんでしまい、もうメモリ不足(正確には
データベースのプロセス・セッション用に割り当て可能な上限値を超えてしまう)
で新たな接続は認めないというエラーが返ってきている。
いわゆるゾンビプロセスは、時間が経てば無くなっていくため、下記の対処を
行わなくても、待てば解決する場合もある。(端末の台数によるが1時間半程度)
■方針
接続が残っているセッションを強制終了する
■手順
①SYSでログインする
sqlplus sys/パスワード@detabase名 as sysdba
②表示幅の調節
set linesize 1000
③セッションを確認する
最大値に達していれば、エラー原因と考えてよい
(新たな接続が制限され、なかなかつながらない状況)
SELECT
RESOURCE_NAME リソース名,
CURRENT_UTILIZATION 現在数,
MAX_UTILIZATION 最大数,
LIMIT_VALUE 上限
FROM
V$RESOURCE_LIMIT
WHERE
RESOURCE_NAME IN ('processes','sessions');
リソース名 現在数 最大数 上限
------------------------------------------
processes 198 200 200
sessions 197 200 200
④具体的なセッションを一覧表示する
machine が端末名、 LOGON_TIME がログイン時間、
sid と serial# がセッションを強制終了する際に必要となる項目
SELECT
S.machine,
TO_CHAR(S.LOGON_TIME, 'YYYY/MM/DD HH24:MI:SS') LOGON_TIME,
S.sid,
S.serial#,
P.PID ORACLE_PID,
P.SPID OS_PID,
S.STATUS,
S.USERNAME ORACLE_USER,
S.OSUSER OS_USER,
S.TERMINAL,
S.PROGRAM
FROM
V$PROCESS P
LEFT OUTER JOIN V$SESSION S
ON P.ADDR = S.PADDR
WHERE
P.BACKGROUND IS NULL AND
P.PID > 1
ORDER BY
S.machine,
TO_CHAR(S.LOGON_TIME, 'YYYY/MM/DD HH24:MI:SS');
⑤重複しているセッションを強制終了する
同一マシーンで、古いログイン時間で、STATUSがACTIVEでなければ、
強制終了の対象として検討する。
間違えた場合は、危険を伴うためユーザーの責任で実行すること
文法:alter system kill session 'sid,serial#';
例:alter system kill session '100,123'
実行後、commitする
■対策
物理メモリに余裕があれば、プロセス数、セッション数の上限を増やす。
ただし、PGAのメモリ割り当てが少ないと別のエラー原因になるため、
単純に増やせばいいわけではない。また、ORACLEインスタンスの再起動が
必要になるため、実行する際は注意が必要である。まずは自分のローカル環境で
試しに増やして実験してみるとよいだろう。
SYSユーザーにて以下を実行
alter system set processes = xxx scope=spfile;
alter system set sessions = xxx scope=spfile;
データベースにいきなり接続できなくなると影響がかなり大きいため
日頃から、プロセス数、セッション数、SGA、PGAのメモリ状況などは
チェックするようにしておきたい。
ORA-12516: TNS: リスナーは、一致するプロトコル・スタックが使用可能なハンドラを
検出できませんでした。
■原因
停電などでHUBの電源が落ちた際、クライアントPCとデータベースが一度にたくさん
切断される場合がある。このとき、データベース側には、これまで接続していた
プロセス・セッションが残っている。復旧後に、クライアントPCから接続されると
新たにプロセス・セッションがデータベースのメモリに割り当てされる。
つまり、サーバ上のメモリ使用量が倍近くに膨らんでしまい、もうメモリ不足(正確には
データベースのプロセス・セッション用に割り当て可能な上限値を超えてしまう)
で新たな接続は認めないというエラーが返ってきている。
いわゆるゾンビプロセスは、時間が経てば無くなっていくため、下記の対処を
行わなくても、待てば解決する場合もある。(端末の台数によるが1時間半程度)
■方針
接続が残っているセッションを強制終了する
■手順
①SYSでログインする
sqlplus sys/パスワード@detabase名 as sysdba
②表示幅の調節
set linesize 1000
③セッションを確認する
最大値に達していれば、エラー原因と考えてよい
(新たな接続が制限され、なかなかつながらない状況)
SELECT
RESOURCE_NAME リソース名,
CURRENT_UTILIZATION 現在数,
MAX_UTILIZATION 最大数,
LIMIT_VALUE 上限
FROM
V$RESOURCE_LIMIT
WHERE
RESOURCE_NAME IN ('processes','sessions');
リソース名 現在数 最大数 上限
------------------------------------------
processes 198 200 200
sessions 197 200 200
④具体的なセッションを一覧表示する
machine が端末名、 LOGON_TIME がログイン時間、
sid と serial# がセッションを強制終了する際に必要となる項目
SELECT
S.machine,
TO_CHAR(S.LOGON_TIME, 'YYYY/MM/DD HH24:MI:SS') LOGON_TIME,
S.sid,
S.serial#,
P.PID ORACLE_PID,
P.SPID OS_PID,
S.STATUS,
S.USERNAME ORACLE_USER,
S.OSUSER OS_USER,
S.TERMINAL,
S.PROGRAM
FROM
V$PROCESS P
LEFT OUTER JOIN V$SESSION S
ON P.ADDR = S.PADDR
WHERE
P.BACKGROUND IS NULL AND
P.PID > 1
ORDER BY
S.machine,
TO_CHAR(S.LOGON_TIME, 'YYYY/MM/DD HH24:MI:SS');
⑤重複しているセッションを強制終了する
同一マシーンで、古いログイン時間で、STATUSがACTIVEでなければ、
強制終了の対象として検討する。
間違えた場合は、危険を伴うためユーザーの責任で実行すること
文法:alter system kill session 'sid,serial#';
例:alter system kill session '100,123'
実行後、commitする
■対策
物理メモリに余裕があれば、プロセス数、セッション数の上限を増やす。
ただし、PGAのメモリ割り当てが少ないと別のエラー原因になるため、
単純に増やせばいいわけではない。また、ORACLEインスタンスの再起動が
必要になるため、実行する際は注意が必要である。まずは自分のローカル環境で
試しに増やして実験してみるとよいだろう。
SYSユーザーにて以下を実行
alter system set processes = xxx scope=spfile;
alter system set sessions = xxx scope=spfile;
データベースにいきなり接続できなくなると影響がかなり大きいため
日頃から、プロセス数、セッション数、SGA、PGAのメモリ状況などは
チェックするようにしておきたい。
2012年2月11日土曜日
共有フォルダにあるEXEを起動する方法
以前のVB6の時代では、サーバ上にあるEXEのショートカットを
ローカル端末に作成し、簡単に起動できていた。
.NETになってからは、セキュリティが厳しくなり、いくつか設定が必要である。
手順は以下の通りである。
まず起動させたいEXEのショートカットをローカルに作成する。
■実行してみると、以下のエラーが出る場合がある
「発行元を確認できませんでした。このソフトウェアを実行しますか?」
「このファイルには、発行元を検証できる有効なデジタル署名がありません。
信頼できる発行元のソフトウェアのみ実行して下さい。」
対処方法は、以下の2点
1.対象のEXEのパスは、IPアドレスでなく、PC名で指定する
ショートカットを右クリックして、プロパティを選択
リンク先が「\\192.168.XXX.XXX\・・・」となっている箇所を
「\\自分のPC名\・・・」のように変更する
※自分のPC名とは、マイコンピュータを右クリックして
プロパティを選択し、コンピュータ名のタブを選択する。
フルコンピュータ名のところに表示されている名称のことである。
「.」が付いているがこれは不要
2.EXEがある場所をゾーン追加する
コントロールパネル→インターネットオプション
「セキュリティ」のタブを選択
「ローカルイントラネット」を選択
「サイト」のボタンを押下
「詳細設定」のボタンを押下
このWEBサイトをゾーンに追加する欄に、EXEがあるパス
「\\自分のPC名\・・・」を貼り付けて追加ボタンを押下する。
登録されると「file://自分のPC名」と表示される。
■再度、EXEを実行してみると、以下のエラーが出る場合がある
「System.Security.Policy.PolicyException: 必要なアクセス許可を取得できません。」
これは、.NETのセキュリティポリシー設定が不足している場合である。
対処方法は、以下の通り
・コマンドプロンプトを起動する
・以下のコマンドを実行する
「cd c:\Windows\Microsoft.NET\Framework\v2.0.50727」
・以下のコマンドを実行する
「caspol -m -ag 1 -url file://\\\自分のPC名\EXEがあるパス\* FullTrust」
以上の手順が完了すると、ローカル端末から無事EXEが起動するはずである。
今回の手順は、閉じたネットワークを想定しており、インターネットに接続できる
ような端末では、セキュリティ設定を十分考慮する必要がある。
ローカル端末に作成し、簡単に起動できていた。
.NETになってからは、セキュリティが厳しくなり、いくつか設定が必要である。
手順は以下の通りである。
まず起動させたいEXEのショートカットをローカルに作成する。
■実行してみると、以下のエラーが出る場合がある
「発行元を確認できませんでした。このソフトウェアを実行しますか?」
「このファイルには、発行元を検証できる有効なデジタル署名がありません。
信頼できる発行元のソフトウェアのみ実行して下さい。」
対処方法は、以下の2点
1.対象のEXEのパスは、IPアドレスでなく、PC名で指定する
ショートカットを右クリックして、プロパティを選択
リンク先が「\\192.168.XXX.XXX\・・・」となっている箇所を
「\\自分のPC名\・・・」のように変更する
※自分のPC名とは、マイコンピュータを右クリックして
プロパティを選択し、コンピュータ名のタブを選択する。
フルコンピュータ名のところに表示されている名称のことである。
「.」が付いているがこれは不要
2.EXEがある場所をゾーン追加する
コントロールパネル→インターネットオプション
「セキュリティ」のタブを選択
「ローカルイントラネット」を選択
「サイト」のボタンを押下
「詳細設定」のボタンを押下
このWEBサイトをゾーンに追加する欄に、EXEがあるパス
「\\自分のPC名\・・・」を貼り付けて追加ボタンを押下する。
登録されると「file://自分のPC名」と表示される。
■再度、EXEを実行してみると、以下のエラーが出る場合がある
「System.Security.Policy.PolicyException: 必要なアクセス許可を取得できません。」
これは、.NETのセキュリティポリシー設定が不足している場合である。
対処方法は、以下の通り
・コマンドプロンプトを起動する
・以下のコマンドを実行する
「cd c:\Windows\Microsoft.NET\Framework\v2.0.50727」
・以下のコマンドを実行する
「caspol -m -ag 1 -url file://\\\自分のPC名\EXEがあるパス\* FullTrust」
以上の手順が完了すると、ローカル端末から無事EXEが起動するはずである。
今回の手順は、閉じたネットワークを想定しており、インターネットに接続できる
ような端末では、セキュリティ設定を十分考慮する必要がある。
登録:
投稿 (Atom)