miau's blog?

«Prev | 1 | 2 | 3 | 4 | Next»

2005年 4月 07日 (木曜日)

FINDSTR

- Work on miau's blog?
仕事中に「DOS の FINDSTR コマンドで 3<TAB><TAB> で始まる行を検索するにはどうすればいいの?」なんて質問を受けまして。

無駄にてこずったのでメモ。 [Read More!]
15:32:38 - miau - No comments - No Trackbacks - Permalink

2005年 3月 20日 (日曜日)

SQL の最適化とか DBMS の運用とか

- Work on miau's blog?
そういえば幕張でトラブルに居合わせたんですが。
なんかテスト環境で SQL の結果件数を確認する必要があるとかで、こんな SQL 投げてました。

SELECT COUNT(emp_id)
FROM MonthlyWorktime A
WHERE work_time = (SELECT MAX(work_time) FROM MonthlyWorktime WHERE emp_id = A.emp_id)

(実際にはテーブル名とか違いますが、まぁこんなノリだと思ってください)

この SQL が 1 時間とか経っても終わらないらしく。

ここで MonthlyWorktime のテーブル件数は 7 万件程度。
ざっと考えると(work_time にインデックスは張れないので)テーブル全件検索が 2 回行われている状態のはずで。
14 万件程度の検索で 1 時間もかかるわけがありません。

んー・・・もしかして、DB2 のオプティマイザって頭悪い?
ということで、試しに代替の SQL を投げてもらいました。

SELECT COUNT(A.emp_id)
FROM MonthlyWorktime A,
(SELECT emp_id, MAX(work_time) AS max_work_time FROM MonthlyWorktime GROUP BY emp_id) AS B
WHERE A.emp_id = B.emp_id
AND A.work_time = B.max_work_time


まぁやってることは同じなんですが、これだと一瞬で終わりました。
前者の SQL だと 7 万件検索して、その結果に対してそれぞれ副問合わせやってたってこと?
まぁ 49 億件も検索するならある程度遅くてもわかるような気も。

んー・・・それにしても Oracle や SQLServer だと、どっちの SQL でも同じアクセスプランができそうなもので。
「DB2 のオプティマイザは頭悪いので、開発者側でもある程度効率的な SQL を書きましょう」ってこと?

とか思ってたんですが、よくよく聞いてみると前者の SQL は本番環境でも毎晩実行されているそうで。
本番のデータはテスト環境よりも遥かに多いはずだから、この調子だと一晩で終わらないような・・・

というところでやっと気づきました。
そういえば本番環境は毎日統計情報を更新しているんでした。
一方テスト環境は統計情報を更新してないので、アクセスプランが最適化されていなかったと。

統計情報の更新とか、どうも見落としがちだけど気をつけないといけないなー、と思いました。
ちょうど見かけた記事にもリンク張っておこう。
@IT:RDBMSアーキテクチャの深層(2) Page 2


2005/03/22 よく見ると SQL 間違ってたので修正。
あとテーブル名が Montyly とかなってたのでそこも修正。なぜ気づかないのか謎。
03:26:53 - miau - No comments - No Trackbacks - Permalink

2005年 3月 18日 (金曜日)

ヘルプ作業@幕張

- Work on miau's blog?
以前幕張で鬱プロジェクトやってたという話は書きましたが。
今メインでやってるプロジェクトが暇なのを見抜かれて、ここ一週間ほどヘルプに行ってました。

ということでまとめ。長いので注意。
[Read More!]
22:12:34 - miau - No comments - No Trackbacks - Permalink

2004年 10月 26日 (火曜日)

xargs

- Work on miau's blog?
邪魔なファイルを除去しつつファイルを固めたくて

find ./hoge -type f | egrep -v '\.[ao]$' | xargs tar cvf hoge.tar


としたけど、なんかファイルが足りないような。
よくよく見てみると、末尾のほうのファイルだけ入っているらしい。

man xargs とかしてみると、
「LINE_MAX 以上は読まれません。適当なところで切られて何度かコマンド実行されます」
的なことが書いてあった。仕方ないので

touch dummy.txt
tar cvf hoge.tar dummy.txt
find ./hoge -type f | egrep -v '\.[ao]$' | xargs tar rvf hoge.tar


とか。なんかもっといい方法ありそうな。



・・・で、「なんかいい方法ないですかー?」という流れで書こうと思ったんですが、よく見ると

The xargs command limits the command line length.
When the constructed command line runs, the combined Argument and environment
lists can not exceed ARG_MAX bytes. Within this constraint, if you do not
specify the -n or the -s flags, the default command line length is at least the
value specified by LINE_MAX.


だそうで。
要するに -s と -n 指定すればいいんですね。何やってんだか。
22:35:56 - miau - No comments - No Trackbacks - Permalink

2004年 7月 29日 (木曜日)

bat

- Work on miau's blog?
ひさびさに仕事関係のネタ。

ログファイルを今日の日付にリネームしてとっておきたいようなこととか、よくあると思います。
今までバッチファイルで日付を取得する方法って知らなかったんですけど(date /t とかやっても「2004/07/29 木」とか取得して使い物にならなかったりして)

>echo %DATE%
木 2004/07/29

>echo %TIME%
0:13:50.86

>echo %USERNAME%
Administrator


みたいな感じで取得すればいいらしい。

このままじゃ使い物にならないけど、substr っぽいことをやりたければ

>echo %DATE:~2,4%
2004


とかなんとかやって、set で組み立てれば OK と。


・・・って、知ってる人にとっては常識なんだろうなぁ。

思えば、私は入社以前、本とかほとんど読まずに Web ページから知識仕入れてました。
そういう体系的でない知識ってのは結構抜けがあるので注意しないとなー、とか思いました。

特にこういう基本的な部分は大学時代に仕入れたネタだから、結構怪しかったりするんですよね・・・。
大学のころは「JPEG は日本で開発された数少ないフォーマット」というどこかの Web ページの説明を信じてましたし。
JPEG = Joint Photographic Experts Group であって Japan とは(たぶん)何の関係もないってのに。
00:20:06 - miau - No comments - No Trackbacks - Permalink

2004年 5月 21日 (金曜日)

binary な世界

- Work on miau's blog?
もう一ヶ月くらい前の話ですが、VB で作成したツールにバグがあるとパートナーさんから指摘されました。
親切にもデバッグまでやってくれたらしく「○○のカウントを取得する部分で、こちらの環境では 352321536 という大きな値が取得されてしまうのでオーバーフローを起こしているようです。境界チェックのコードを追加してください」とのこと。

えーと。このカウントっていうのはデータベースのテーブル数みたいなもので。いくらなんでもそれはないだろ、と思ったわけですが。

さて、バグの原因に見当がつくでしょうか?

[Read More!]
08:15:40 - miau - No comments - No Trackbacks - Permalink

2004年 4月 20日 (火曜日)

予実管理

- Work on miau's blog?
どの作業にどれくらいの時間を費やしたか、というのを毎日記録しているのですが。

「えーと・・・昨日は10時出勤で寝たのが4時くらいだから
 24 - (10 - 4) - 1(昼休み)= 18
 で 17 時間か・・・」

とかなんとか
 24h - 睡眠時間
の引き算になってるのがなんか嫌です。

普通に (退社時刻) - (出社時刻) で計算したい。
08:49:01 - miau - No comments - No Trackbacks - Permalink

2004年 4月 15日 (木曜日)

風邪

- Work on miau's blog?
先週末に風邪ひいて連泊記録は1ヶ月ほどで終了。
ちなみに風邪ひいた原因は・・・もちろん無茶な生活で抵抗力が落ちてたんだろうけど、それ以上に会社の空調に問題が。

夕方になるとむぁっと暑くなる→薄着になる→夜中になると次第に冷える(この時は疲れ果てて睡眠中)

というのを繰り返した結果ではないかと。
21:49:18 - miau - No comments - No Trackbacks - Permalink

2004年 4月 09日 (金曜日)

Becky! の通常検索

- Work on miau's blog?
スレッド表示にしている場合。

-hoge
Re: hoge
Re[2]: hoge

となっていた場合は Re: hoge や Re[2]: hoge の中も検索してくれるけど、

+hoge

みたいに折りたたまれてると Re: hoge や Re[2]: hoge は検索対象にならないらしい。

対応策としては
・一時的にスレッド表示を解除して検索
・クエリー検索
のどちらか?
オプション設定からは見つからなかったような。

これまで仕事で「そんなメール届いてないっすよ?」みたいな場面が何度かあったけど、実は検索の仕方が悪かったのかも・・・。
08:27:06 - miau - No comments - No Trackbacks - Permalink

2004年 4月 08日 (木曜日)

DECIMAL

- Work on miau's blog?
同僚が作ったプログラムで怪しげな処理を見かけたのでちょっと確認。

怪しげな処理っていうのは、DECIMAL のフィールドを比較処理。
(1) VB の ADODB.RecordSet で DECIMAL 型のフィールドを普通に取得
(2) CStr$() で文字列に変換
(3) 文字列の比較
とかやってて。それだと 11 < 2 とか評価されちゃうのでは?と思ったわけで。

とりあえず DB2 で試してみた。
db2 => CREATE TABLE TEST (ID DECIMAL(10))


db2 => select id, cast(id as char(12)) from test

ID 2
------------ ------------
0. 0000000000.
1. 0000000001.
2. 0000000002.
10. 0000000010.
-1. -0000000001.
-2. -0000000002.

6 レコードが選択されました。

あれ。CAST した場合は 0 でパディングされるのね。
ということは、場合によっては文字列に変換後でも問題ないんだろうな。
ま、一応確認。

db2 => select id, cast(id as char(12)) from test order by 1

ID 2
------------ ------------
-2. -0000000002.
-1. -0000000001.
0. 0000000000.
1. 0000000001.
2. 0000000002.
10. 0000000010.

6 レコードが選択されました。

CHAR にキャストした後も↑みたいな大小関係があればいいんだけど・・・

db2 => select id, cast(id as char(12)) from test order by 2

ID 2
------------ ------------
-1. -0000000001.
-2. -0000000002.
0. 0000000000.
1. 0000000001.
2. 0000000002.
10. 0000000010.

6 レコードが選択されました。

やっぱりダメでした。
負数は代償関係が逆になってしまいますね。
この方法での比較は フィールド値 > 0 が保証されている場合のみ有効、と。


で・・・ふと自分の PC に SQLServer がインストールされているのを思い出し、この環境でも試してみた。

1> select id, cast(id as char(10)) from test
2> go
id
------------ ----------
0 0
1 1
2 2
10 10
-1 -1
-2 -2

(6 件処理されました)

おー、これこれ。当初は CAST したらこう(0 埋めされず、左寄せに)なると思ってたんだよね。
ということは・・・。

1> select id, cast(id as char(10)) from test order by 1
2> go
id
------------ ----------
-2 -2
-1 -1
0 0
1 1
2 2
10 10
(6 件処理されました)

これはまぁ当然の結果として・・・

1> select id, cast(id as char(10)) from test order by 2
2> go
id
------------ ----------
0 0
1 1
-1 -1
10 10
2 2
-2 -2

(6 件処理されました)

こうな・・・る・・・あれ?
負号の位置が予想と違う・・・。
・・・まぁ SQLServer の照合順序って結構特殊だし、こんなもんかも。


なんか環境によって色々違いそうなので、結局 VB も試してみることに。
同僚がやってたように、CAST は行わず、CStr$() による変換。
    Dim cnn As New ADODB.Connection
Dim rs As New ADODB.Recordset

cnn.Open "dsn=hoge;uid=hoge;pwd=hoge;"

Set rs = cnn.Execute("SELECT ID FROM TEST")
Do While rs.EOF = False
Debug.Print "[" & CStr$(rs.Fields(0)) & "]"
rs.MoveNext
Loop

cnn.Close

超手抜きコード。さて、結果は・・・

[0]
[1]
[2]
[10]
[-1]
[-2]

どうやら左寄せの文字列になってしまう模様。やっぱダメじゃん。


ということで、結論。
INTEGER とかに収まりきらない DECIMAL はできるだけ DB 上で比較しましょう、と。
22:09:14 - miau - 1 comment - No Trackbacks - Permalink

2004年 4月 07日 (水曜日)

SELECT 文 で NULL

- Work on miau's blog?
SELECT 文で NULL をベタ書きすると、エラーになってしまう。
(とりあえず DB2 でのお話。今ほかの DBMS 環境ないので。)

db2 => SELECT ID, VALUE, NULL FROM TEST

SQL0206N 使用されているコンテキストで、"NULL" は無効です。 SQLSTATE=42703

ということで、とりあえず NULLIF で対応。

db2 => SELECT ID, VALUE, NULLIF(0, 0) FROM TEST

ID VALUE 3
------------ ---------- -----------
1. aaa -
2. あああ -

ほかにいい方法ありますかね?

ちなみに、なんで NULL を選択する必要があるのかというと、INSERT INTO 〜 SELECT 〜 を動的に生成していて、条件分岐で NULL を挿入したいから。

char strFormat[] = "INSERT INTO TEST SELECT ID, VALUE, %s FROM TEST WHERE ID=%d";

sprintf(strSql, strFormat, (intSomeFlag) ? ("0") : ("NULLIF(0, 0)"), intId);

EXEC SQL EXECUTE IMMEDIATE :strSql;

あ。ちなみに CHAR やら VARCHAR の列の場合は NULLIF('', '') とかやって型合わせないとダメっぽい。
07:51:28 - miau - 2 comments - No Trackbacks - Permalink

2004年 4月 04日 (日曜日)

const 修飾子

- Work on miau's blog?
今日も出勤とかしてますが。
C の const 修飾子周りでてこずってました。

#include <stdio.h>
#include <string.h>

void move_next(const char **pp)
{
if (IsDBCS(**pp)) {
(*pp) += 2;
} else {
(*pp)++;
}
}

int main()
{
char str[] = "hogeほげ";
char *p = str;

while (*p != '\0') {
if (IsDBCS(**pp)) {
/* なんか処理 */
} else {
*p = toupper(*p);
}
move_next(&p);
}

return 0;
}


これをコンパイルするとエラー発生。
move_next() は const char ** を渡すべきであって char ** は渡しちゃダメなんだそうで。

const char * に char * を代入したりできるから、てっきり上記も OK だと思っていたんだけど。

	const char *q;

:
:

q = p;
move_next(&q);

(これなら文法的には OK。ただここでやりたいことは実現できてない。)

move_next() の宣言から const を外せばいいんですけど。見てのとおり move_next() の中で文字列を操作しているわけじゃないので、気持ち悪い。

んー・・・これって C の仕様がおかしいんじゃないの?
とか思ったけど、よく考えると C++ のオーバーロードとかそのへんに対応するためなのかも。つまり

void move_next(const char **pp);
void move_next(char **pp);


を別の関数として実装できるから、区別できないと困るわけだ。

結局

	move_next((const char**)&q);


とするしかないっぽい。キャストは極力避けたい気もするんだけど、仕方ないか。



(2004/08/29 追記)

すいません。
> よく考えると C++ のオーバーロードとかそのへんに対応するためなのかも。
ってとこ、思いっ切り嘘ついてます。
C FAQ 11.10 参照のこと。

確かにオーバーロード対応だったら
> const char * に char * を代入したりできる
ってのが理屈に合わないですね。
23:16:21 - miau - No comments - No Trackbacks - Permalink

2004年 3月 31日 (水曜日)

そういえば

- Work on miau's blog?
昨日は客先(みたいなもの)から直帰して、シャワー浴びたとこで力尽きてしまいました。
家で睡眠とるのは10日ぶりですが、たまには布団で寝たほうがいいみたいです。

起きたら 23:30 とか。まぁ終電で出社して仕事進めてるわけですが。
03:39:26 - miau - No comments - No Trackbacks - Permalink

2004年 3月 25日 (木曜日)

Help Decompiler

- Work on miau's blog?
SPREAD というコンポーネント、VB の世界では結構メジャーらしいですね。

この SPREAD、今回私も使わざるを得ない状況になってしまったんですが、各プロパティが何を意味するのかイマイチわからなくて。
ヘルプファイルをいちいち辿ればわかるけど、それは面倒。

<プロパティ名>:<説明>

みたいな一覧を作れたらいいんだけど・・・。

ということで発見した WinHelp → RTF の変換ツール。
Help Decompiler
一気に読めるので結構便利。
結局一覧を作らなくても目的の機能を見つけられたし。
なかなかオススメです。
01:55:53 - miau - No comments - No Trackbacks - Permalink

2004年 3月 21日 (日曜日)

lint

- Work on miau's blog?
数日前、実は AIX にも lint が入ってることに気づいた。てっきり Solaris にしか入ってないと思ってたんだけど。

今日(ええ。今日も仕事です)、プログラムがバグってたので試しに使ってみた。
数十行の警告の中に、気になるメッセージ発見。

「変数○○は使用されてません」

ん?その変数使わないはずないだろうに。
と思ったらそこが原因で動いてないことが判明。
デバッグにハマったら1、2時間は無駄にしたかもしれない。

ということで lint、今後積極的に活用する所存でございます。
16:26:55 - miau - No comments - No Trackbacks - Permalink
«Prev | 1 | 2 | 3 | 4 | Next»