• 締切済み

select count(*) の性能

業務アプリケーションで次のSQL文を実行すると非常に時間がかかっています。 "select count(*) from テーブル名 where カラムA='値B'" このテーブルは200万件以上のレコードが存在していて、カラムAには索引が作成されています。DBのOPTIMIZERの処理を見ると(1)索引検索をした後で(2)対象レコードのROWIDを取得して(3)その後FETCH処理をしているのですが、(3)のFETCHの処理が非常に時間がかかっています。どうしたらこの検索を早くできるかヒントがあれば教えて下さい。私のしろうと考えでいくと、DBがどうして(3)のFETCHの処理をしているのかもわかりません。よろしくお願いします。

みんなの回答

  • bin-chan
  • ベストアンサー率33% (1403/4213)
回答No.4

> テストのつど実施するようにしております。 「表領域の離散」は影響しませんか? WindowsNTでは「NTFSのデフラグは不要だ!」といってたのに 2000にはしっかり機能が実装されてるぐらいなので。

satuki5
質問者

お礼

ありがとうございます。結果的に問題は解決しました。私の説明不足だったのですが、実はwhere句で条件指定しているカラムがもう一つありまして、別々のインデックスだったのを一つの複合インデックスにしたら劇的に早くなりました。いろいろとありがとうございました。

  • redbean
  • ベストアンサー率38% (130/334)
回答No.3

count(*) の代りに count(カラムA) とでもすれば、 速くなるでしょう。

satuki5
質問者

お礼

ありがとうございます。結果的に問題は解決しました。私の説明不足だったのですが、実はwhere句で条件指定しているカラムがもう一つありまして、別々のインデックスだったのを一つの複合インデックスにしたら劇的に早くなりました。

  • bin-chan
  • ベストアンサー率33% (1403/4213)
回答No.2

あーーごめんなさい。索引ついてるんですね。失礼しました。 ちなみに200万件に対して「値」は何種類ぐらいでしょうか? OracleならBITMAPインデックスを検討するのが良いかも? 全件に対して0.01%以下の件数ならメリットがあるはず。 なお、索引がついていても、頻繁にレコードの追加・削除が行われるのなら いっぺん再編成してみるのも良いでしょう。 (EXPORT&IMPORT、DROP&CreateIndex)

satuki5
質問者

お礼

アドバイスありがとうございます。索引の「値」の種類は600種類程です。UDBなのでビットマップ索引はオプティマイザーが必要だと判断した時に処理の中で一時的に作成されて明示的には作成できません。 ちなみにoracleで言うところの索引構成表を作成したりもしましたが、時間がかかっている部分は索引検索の部分ではなくてFETCHの部分なので、特にパフォーマンス上のメリットも得られませんでした。 補足いたしますと当テーブル上ではテスト環境にあり、テーブルの再作成と統計表のREFRESHはテストのつど実施するようにしております。

  • bin-chan
  • ベストアンサー率33% (1403/4213)
回答No.1

カラムAに索引をつけることが最も重要と思います。 where句つけずに全件の方が速いでしょ?

関連するQ&A

  • COUNTの使い方

    MySQL4.0.26とPHPを使ってとあるシステムを構築しています。 AとBというテーブルがあって、それぞれのテーブルに登録してあるレコード数の合計を求めたいのですが、こういう場合はできるのでしょうか? SELECT count(*) FROM テーブルAでテーブルAのレコード数は求められますが、SELECT COUNT(*) FROM テーブルA、テーブルBとするとおかしな件数になってしまいます。 できれば一つのクエリで処理したいと思っているのですが。 初心者的質問ですいません。宜しくお願いします。

  • COUNT(*)の使い方

    COUNT(*)の使い方が分からないので質問します。 直接のSQLでCOUNT(*)を使ってレコード数を表示させることはできましたが PHPでのSQLではCOUNT(*)をPHPのソースの変数に代入する方法が分かりません。 $sql = 'SELECT ip, COUNT(*) FROM webdb'; $ret = mysql_query($sql); $rowval = mysql_fetch_row($ret); この場合、$rowval[1] がテーブルwebdbのレコード数だと 思いましたが、間違っているところはございませんか?

    • ベストアンサー
    • MySQL
  • 二つのcount()を一文で

    Select count(COLUMN_A) from TABLE_A where USERID=1 and FLAGS=1; Select count(COLUMN_A) from TABLE_A where USERID=1 and FLAGS=2; を1つの文で取得する方法はないでしょうか?

    • ベストアンサー
    • MySQL
  • count関数の値をwhere句で使用する方法について

    宜しくお願い致します。 例えば、下記の様にデータを検索します。 select column1,count(column2) as column2_num from hoge_table group by column2_num すると、検索結果にはcolumn1のそのままの値と、column2の合計数が表示されると思います。 このcolumn2の合計数に対してwhere句で絞込みを行う方法はありませんか? asで定義した値をそのままwhere句で使用できないとの事なので、 select column1,count(column2) as column2_num from hoge_table where count(column2) = '1' group by column2_num とやってみたんですが、検索出来ませんでした。 ご存知の方、ご教授の程、宜しくお願いいたします。

    • ベストアンサー
    • MySQL
  • #1136 - Column count doesn't match value count at row 1 の原因について

    テーブルaでtestカラムがあるにも関わらず以下のSQLを実行すると、 #1136 - Column count doesn't match value count at row 1 のエラーとなります。 UPDATE a SET test = '0' WHERE a_id = '1' AND b_id = '2' AND c_id = '3' トリガが動いていないか等、調べたのですが原因がわかりません。 考えられる原因は何があるでしょうか? ちなみに、以下のSQLでは1件のレコードが取得できます。 SELECT test FROM a WHERE a_id = '1' AND b_id = '2' AND c_id = '3'

    • ベストアンサー
    • MySQL
  • ORACLE 索引検索について

    ORACLE初心者で索引について勉強しています。 そこでORACLEの索引(Bツリー)検索について2点程質問させていただきます。 (1)索引を用いるとI/O処理が少なくなりアクセスが高速になるということはわかったのですが、そのI/O処理とはプロセスとメモリ間のやりとりに関するI/O処理という認識で間違いないのでしょうか? (2)索引付きと索引なしのカラムを抽出条件にして検索した場合、まず索引付きのカラムから検索を行い、そのROWIDを元に索引なしのカラムのデータを取得して対象データかどうかの判断を行うのでしょうか?

  • COUNT関数が上手く設定できない

    COUNT関数が上手く設定できなくて困っています。 DBに案件テーブルと担当者テーブルを設定し、案件に紐付く担当者を検索できるようにしようと思っています。 案件に対して複数の担当者が担当になることがあり、案件テーブルに担当者テーブルをLeft Joinして、最後にGroup byでグルーピングすることによって案件自体は検索できるのですが、ページネーションのためCOUNT関数を使って案件数を求めようとすると、正しい数値が得られません。 select count(a.id) counts // ここをa.* とすることで案件情報を検索することはできます。 from ANKEN a left join TANTOU t on a.id = t.id where flag = 0 group by a.id 正しい件数を取得するにはどのようにすれば良いでしょうか?

    • ベストアンサー
    • MySQL
  • SELECT COUNTで取得した結果の表示

    phpで検索結果画面の制作を勉強中です。 pdoでmysqlデータベースに接続しています。 現在、検索フォームの作成を勉強中です。 検索用のフォームに入力された文字に類似しているという条件(あいまい検索)のもと、 添付画像の上のようなデータベーステーブル内をSELECT COUNTし、 添付画像の下のように、検索に該当するそれぞれのカラムのデータと、そのデータがいくつ存在しているのかを表示させたいです。 SELECT COUNTでGROUP BYを使用すれば結果が取得できると教えていただき、以下のようなphpを記述しました。 //フォームに入力されたテキストをGETで渡し、プログラムで取得し、あいまい検索に対応させる。 $search = '%'.$_GET['search'].'%'; //現在表示している結果表示ページのページ数をURLから取得 $page = $_GET['page']; //SQLのLIMIT句用にデータのいくつめから取得するか$limitに入れる $limit = ($page-1) * 20; //該当するものをグループ化し、それぞれのデータ数をカウントする try{ $stmt=$db->prepare('SELECT COUNT 【住所】 FROM 【顧客情報】 WHERE search like :search GROUP BY 【住所】 LIMIT :limit , 20'); $stmt->bindValue(':search',$search,PDO::PARAM_STR); $stmt->bindValue(':limit',$limit,PDO::PARAM_INT); $stmt->execute(); }catch(PDOException $e){ $error = "エラー:".$e->getMessage(); } while($row = $stmt->fetch(PDO::FETCH_ASSOC)){ print $row['【住所】']; } ※検索フォームのタグは省略しています。 ※データベース接続は$dbで行っています。 ※該当したデータを1ページにつき、20件ずつ表示したいのでLIMIT句を使用しています。 実行したところ、結果はおろか、エラーも何も表示されませんでした。 個人的にはSQL文に間違えがあるというよりも、 while文以降で取得したデータの表示ができていないのではないかと思いますが、 「SELECT COUNT」の結果表示の方法をネットで調べても 答えになるものが中々見つかりませんでした。 また、添付画像の下のように、 取得したデータ名とそのデータの件数を一緒に表示するプログラムが理想なので、 どなたかご教授頂けると有難いです。 ご回答、よろしくお願いします。 ※ちなみに、正規化については理解しておりますが、今回は例示として住所を使用しました。

    • ベストアンサー
    • PHP
  • テーブルで一番古いレコードだけをSELECTしたい

    テーブルで一番古いレコードだけをSELECTしたいのですが、どうすれば良いでしょうか? ■背景 ・テーブルからデータを取得しようと思ったら、「id」及び「autoincrement」に該当するカラムがありませんでした ・日付に該当するカラムもありません ・「phpMyAdmin」で確認すると、いつも同じ並び順で表示されるので、格納したレコード順で表示されているのではないかと思いました ■質問 ・この時、そのテーブルで一番古いレコードだけをSELECTしたいのですが、どうすれば良いでしょうか? ・where?

    • ベストアンサー
    • MySQL
  • DELETE文とロックについて

    DELETEしようとしているレコードがロックされている場合は、削除せず すぐに処理を戻したいです。イメージ的にNOWAITが最適と思い →DELETE FROM テーブルA WHERE カラムA = 'A' NOWAIT としたいところですが、NOWAITはSELECT文でしか指定できないとのことなのでNGです。 SELECT文で抽出した条件のレコードを削除する場合 →DELETE FROM テーブルA WHERE カラムA =      (SELECT カラムA FROM テーブルA WHERE カラムA = 'A') と出来ます。 又、SELECT文でロック待機時間なしの場合 →SELECT カラムA FROM テーブルA WHERE カラムA = 'A' FOR UPDATE NOWAIT と出来ます。 これらを組み合わせて、ロックされているレコードを削除しようとした場合、 すぐにNGで制御を戻すように、次のように記載してみました。 →DELETE FROM テーブルA WHERE カラムA =    (SELECT カラムA FROM テーブルA WHERE カラムA = 'A' FOR UPDATE NOWAIT) なぜかNGになってしまいます(右カッコがありませんと言われます)。 なぜこの書き方が出来ないのでしょうか? 現在、一度該当のレコードをSELECT文でFOR UPDATE NOWAITをしてから DELETEをしています。 1つレコードを削除したいだけなのに、わざわざSELECT文と DELETE文を発行してしまっています。 こういう場合、他にどのような方法があるのでしょうか? 宜しくお願いします。