[pgsql-jp: 28412] Re: updateの性能を向上
Tamotsu Ebina
ebina @ pluto.dti.ne.jp
2002年 12月 21日 (土) 17:58:43 JST
海老名@インフォテック です。
Iwao Watanabe wrote:
> こんにちは。
>
> ----- Original Message -----
> From: <fukudami @ ntes.nec.co.jp>
> To: <pgsql-jp @ ml.postgresql.jp>
> Sent: Friday, December 20, 2002 8:34 PM
> Subject: [pgsql-jp: 28403] updateの性能を向上
>
>
>
>>現状、普通にupdateを使用してDBを更新しているのですが、どうも
>>望んだ性能が出ません。現在約40万件レコード登録してあるテーブル
>>に対し、下記の様な方式でupdateを実行すると、約15分程度かかって
>>しまいます。更新対象のレコード数はそれほど多くは無い(と言っても
>>ばらつきはありますが)ので、可能ならば2〜3分程度の性能にしたいです。
>>更新対象のレコード数は、一度に500〜3000程度です。
>
>
> 人が見ないようなデータなら少々遅くても、
> コンピュータがせっせと動いてくれるので
> 文句をいう人は、まずいません。
> 40万件のデータ処理に15分が遅いですか?
> 充分早いではないですか。
> 人が同じことを処理して15分で終わるのでしょうか。
>
> (最後はちょっと詭弁)
>
最後は詭弁ですね。
たかだか40万件の処理に15分もかかるようならRDBMSを使う必要はありません。
私のテストプログラム(Java)で 1,000,000 件のインデックス付の
テーブルからランダムに約1000件抽出してUPDATEするのに要した時間を
参考までに示します。
PoatgreSQL7.2.3 ですが
DBサーバ
CPU 2.4GHz Memory 1GB SCSI 10,000RPM x 3 Raid5
アプリケーションサーバ
CPU 1.6GHz Memory 512MB IDE 5400RPM
のスペックで
JDBC 接続 100MB Switching HUB
の環境で実行した結果です。
[2002-12-21 17:06:28.990] SelectUpdateLP01 Start.
pos
[2002-12-21 17:06:29.840] Select Start
[2002-12-21 17:06:50.367] SelectUpdateLP01 End.
count=970
20.527秒です。
1)レコード件数確認(プログラム実行前)
tghakodb=> select count(*) from customer_info;
count
---------
1000000
(1 row)
2)フラッグ付レコード件数確認(プログラム実行前)
tghakodb=> select count(*) from customer_info where delete_flg='D';
count
-------
0
(1 row)
3)フラッグ付レコード件数確認(プログラム実行プログラム実行後)
tghakodb=> select count(*) from customer_info where delete_flg='D';
count
-------
970
(1 row)
tghakodb=> select count(*) from customer_info where delete_flg!='D';
count
--------
999030
(1 row)
1千万件でも同じような結果だったと思います。
15分かかっているとなるとインデックスが働いてなく、全件検索になっている
可能性が高いですね。
vaccum --analyze --table <テーブル名> データベース名
でバキュームをかけ
explain <実行SQL文>
で確認すれば、索引が働いているか分かります。
キー付
kodb=> explain select * from customer_info where branch_cd='001' and
group_cd='001';
NOTICE: QUERY PLAN:
Index Scan using pk_customer_info on customer_info (cost=0.00..102.37
rows=25 width=1097)
EXPLAIN
キー無
kodb=> explain select * from customer_info where group_cd='001';
NOTICE: QUERY PLAN:
Seq Scan on customer_info (cost=0.00..61084.00 rows=5000 width=1097)
EXPLAIN
違いはキー部分がそちらはTEXTで私はCHARとNUMERIC
ですね。
参考までにこちらのテストテーブル
CREATE TABLE CUSTOMER_INFO (
BRANCH_CD CHAR(3) NOT NULL,
GROUP_CD CHAR(3) NOT NULL,
CUSTOMER_CD CHAR(8) NOT NULL,
SEQ_NUM NUMERIC(4) NOT NULL,
CUSTOMER_NAME_KNJ VARCHAR(60),
CUSTOMER_NAME VARCHAR(30),
CUSTOMER_TEL_CD CHAR(1),
CUSTOMER_TEL_NUM VARCHAR(16),
CUSTOMER_POST_NUM CHAR(7),
CUSTOMER_PREF_KNJ VARCHAR(10),
CUSTOMER_DIST_KNJ VARCHAR(40),
CUSTOMER_TOWN_KNJ VARCHAR(40),
CUSTOMER_ADDRESS_KNJ VARCHAR(40),
CUSTOMER_APARTMENT_KNJ VARCHAR(40),
CUSTOMER_PREF VARCHAR(10),
CUSTOMER_DIST VARCHAR(20),
CUSTOMER_TOWN VARCHAR(20),
CUSTOMER_ADDRESS VARCHAR(20),
CUSTOMER_APARTMENT VARCHAR(20),
MAIL VARCHAR(30),
DELETE_FLG CHAR(1),
UPDATE_DATE CHAR(23),
INSERT_DATE CHAR(23)
);
ALTER TABLE CUSTOMER_INFO ADD CONSTRAINT PK_CUSTOMER_INFO
PRIMARY KEY (BRANCH_CD,GROUP_CD,CUSTOMER_CD,SEQ_NUM);
ORACLEでは
where句を
WHERE BRANCH_CD=001 AND GROUP_CD=001 AND CUSTOMER_CD=100010011
AND SEQ_NUM=1;
と書くと、左辺に自動的にto_numeber関数が実行され、結果的に
索引が働かず、全件検索になった経験があります。
このときは、
WHERE BRANCH_CD='001' AND GROUP_CD='001' AND CUSTOMER_CD='100010011'
AND SEQ_NUM=1;
と書く亊によりインデクッスが働きました。
DB2では
SQL0401N 演算 "=" のオペランドのデータ・タイプが一致していません。
とエラーになります。
PostgreSQL7.2.3では検索結果は0件になります。
TEXTタイプのケースでは試したことはありません。
TEXTタイプは互換性から私はほとんど使いません。
商用データベースでは桁数が固定ならCHARを可変ならVARCHARを
使用するのが一般的だと思います。
以上参考になれば。
pgsql-jp メーリングリストの案内