• ベストアンサー

MySQLやSQliteの中のデータ検索速度について

ざっくりとした回答で結構ですので、データベース言語のバージョンについては、あえて記載を省きます。 環境:Apatch、Linux、PHP4、SQlite2 バージョンによって動作が異なるのであれば、その場合には適宜補足します。 なお、私はデータベース言語の知識をそれほど持っていませんので、分かりやすく記述して頂けると大変助かります。 --------------------------- では、本題に移らせて頂きます。 現在、PHP4とSQlite2の組み合わせでスクリプトを制作中なのですが、 その際に、データベース(以下、DB)の中のデータを検索・抽出することがあります。 SQliteのコマンドでは、SELECT文を使った記述になります。 (恐らく、MySQLなどでも同様だと思います。) で、知りたいことは、 DBをどう構築したら、「検索・抽出」速度が遅くなりにくいか(高速になりやすいか)。 これが知りたいわけです。 私が考えている方法は、いくつかあって、それらについて、 速い遅いの意見を覗いたいと思います。 また、もっと良い方法がありましたら、そちらも教えて下さい。 想定しているDBは、例として、簡単に以下のものとします。 例:学年の生徒DB クラスがA組~E組まで5クラスあります。 生徒の、 氏名、性別、クラス、出席番号、生年月日、所属している部活名、担当委員、欠席数 のようなものを記録するDBだと思って下さい。 さて、この例において、以下のどの形式が良さそうでしょうか。 方法1: (DBファイルを1つ用意) DBをCREATEするときに、TABLE名を tbl_all という風に1学年全体で記録するような形式。 方法2: (DBファイルを1つ用意) DBをCREATEするときに、TABLE名を tbl_a ~ tbl_e という風に分け、それぞれのテーブルに各クラスの生徒データを記録するような形式。 方法3: (DBファイルを複数用意) DBをCREATEするときに、クラスごとに、DBファイルを「db_a.sqlite2」~「db_e.sqlite2」のように作成し、それぞれにおいて、TABLEを1つ作り、そこにクラス内の生徒のデータを記録する形式。 どの形式のDBが、速く(もちろん正確に)検索・抽出(SELECT)できるでしょうか。 一般論でも結構です。 また、データ数が多くなるにつれ、速度が逆転するというような場合には、そちらも教えて下さい。 この例では、クラス数が5なので、比較的データは少ないですが、 私が構築しようとしているDBでは、データを1万件以上扱う可能性が高いので、その点も考慮して、アドバイスして頂けると嬉しいです。 以上、よろしくお願い致します。

  • march4
  • お礼率83% (628/754)
  • MySQL
  • 回答数4
  • ありがとう数5

質問者が選んだベストアンサー

  • ベストアンサー
  • notnot
  • ベストアンサー率47% (4848/10261)
回答No.2

ご存じかもしれませんが、よく使う項目でindexを作っておくと検索は速いです。indexをたくさん作りすぎると更新が遅くなりますが。 データが1万件程度なのだったら、あまり速度を気にしなくてもいいと思いますよ。 一般に、テーブルを分割するのは、1秒間に何十件とか何百件の参照・更新処理を行うときに、テーブルを分けて別の物理ディスクに配置するとディスク入出力を独立して行えるので、処理時間が短くて済むという理由です。 あと、sqliteの場合は排他がDB単位でかかるので、DBを分けると言うことも行うようです。 質問に書かれてませんが、おそらく並列処理しないか、しても2-3個くらいだと思うので、1テーブルにまとめる方がいいと思います。

march4
質問者

お礼

ありがとうございました(^^) また何かありましたら、教えて下さいね。

march4
質問者

補足

>ご存じかもしれませんが、よく使う項目でindexを作っておくと検索は速いです。 いえ、全く、ご存じではありませんでした(笑)。 indexという概念について、私には全く知識がないので、 それが何であるか、調べてみますね。 >データが1万件程度なのだったら、あまり速度を気にしなくてもいい 具体的なアドバイスをありがとうございます。 >テーブルを分けて別の物理ディスクに配置するとディスク入出力を独立して行えるので、処理時間が短くて済む つまり、テーブルを分けると、場合によっては検索速度が上がるという解釈で問題なさそうですか? >sqliteの場合は排他がDB単位でかかるので、DBを分けると言うことも行うようです。 「排他」という概念についても、同様に調べようと思います(笑)。 >おそらく並列処理しないか、しても2-3個くらいだと思うので、1テーブルにまとめる方がい 並列処理とは、どういうことを言うのでしょうか。 すみません、本当に、何も知らなくて。。 PHPコードは基本的に上から処理されると思いますが、 並列に処理されるケースというのは、どういうコードの場合なのでしょうか。 例えば、 DBのSELECT文をPHPスクリプト内に2種類続けて書いた場合、 メカの方では、最初のSELECT処理をしつつ、次のSELECT処理も同時並行的に行っていたりするのでしょうか? もし、そういうことを並列処理と言うのであれば、 並列処理を3個くらいすることもあり得ます。 もっとも、3個程度ならば、回答の中にありますように、1テーブルで問題なさそうですね。 示唆に富む回答をありがとうございました。 また何かありましたら、教えて下さい。

その他の回答 (3)

  • yambejp
  • ベストアンサー率51% (3827/7415)
回答No.4

個人情報を管理するだけであれば、SQLよりもむしろLDAP的な処理の 方が管理しやすいかもしれないですね。 今回の例だと欠席数を集計するところは意味があります。 もう少し発展的にたとえば成績を管理集計したりするのであれば より効果が高いです。 個人情報のテーブルについては →氏名、性別、生年月日、 など普遍的なものに関しては、一つのテーブルにまとめた方が 効率的です。 →クラス、出席番号、所属している部活名、担当委員 など、学年が変わったり、なんらかの理由で変わる可能性が高いものは 正規化しておいた方がよいでしょう。 →欠席数 など、時系列なデータにリンクするものは専用の管理テーブルを つかって集計する必要があります。

march4
質問者

お礼

ありがとうございました(^^) また何かありましたら、教えて下さいね。

march4
質問者

補足

アドバイスありがとうございます。 >SQLよりもむしろLDAP的な処理の方が管理しやすいかも LDAP・・・、初めて聞く言葉でした。^^; そして、ザッと調べてみましたが、すぐに理解できるような代物ではない気がして、今のところ保留にしています。 >普遍的なものに関しては、一つのテーブルにまとめた方が効率的 普遍的要素テーブルを1つ用意すると良い、ということですね。 >なんらかの理由で変わる可能性が高いものは正規化しておいた方がよい 正規化、つまり、1つのフィールドに情報を盛りだくさんに詰め込まないようにした方がいい、ということですね。 >時系列なデータにリンクするものは専用の管理テーブルをつかって集計 時系列要素テーブルを1つ用意すると良い、ということですね。 ■以上をまとめると、本問の例で、検索速度を上げるには、 テーブルを少なくとも3つ以上は作った方が良いということになりますか? (「→」の数が3つありましたので…。笑) よって、私が書いた「方法2」に近い形がオススメということになるのでしょうか。 そもそも、「LDAP的な処理」というものが理解できていない私には、今回アドバイス頂いた内容は参考にならないのでしょうか?^^; 自分が理解できているのか、いないのか、分からずに居ます…。笑 すみません、あやふやな補足になりました。苦笑

  • notnot
  • ベストアンサー率47% (4848/10261)
回答No.3

#2です。 >並列処理とは、どういうことを言うのでしょうか。 AさんがそのDBにせっせとデータ入力をしている横で、BさんがDB全体の集計をしているようなものです。Bさんは集計するたびに数字が違うので混乱しています。 別の例で言うと、X銀行のYさんの口座に10,000円残高があったとして、YさんがATMで1,000円下ろしたとします。その処理で、10000を読み込んで1000を引いてと処理している瞬間に、Zさんから5,000円振り込まれたとすると、残高はどうなるでしょう?というのが排他が必要となるケースです。 並行処理をしないのなら、排他も要りません。

march4
質問者

お礼

ありがとうございました(^^) また何かありましたら、教えて下さいね。

march4
質問者

補足

並列処理について、大変よく分かりました! トランザクションに関係するお話なのですね。(たぶん、そうですよね。笑) 具体例を二つもあげて頂いて、親切にどうもありがとうございます。 1つ目の例で完璧に分かりましたが、2つ目を読み、人間愛を感じました。照 話を戻しますと、 私のスクリプトにおいては、並列処理は、、、、ない、と思っていましたが、よく考えてみましたら、 私の作成中のスクリプト群において、データ挿入(INSERT)するスクリプトと、検索抽出(SELECT)するスクリプトが同時期にアクセスされることは充分あり得ますので、 この場合、並列処理が行われる可能性があるということですから、排他についても、適宜考える必要があるということなのでしょうね。 (並列処理が2~3個程度なら、考えなくても良いかなと、というお話でしたね。前レスを振り返り…。) ちなみに、銀行の残高ほど情報の正確性を求めているようなスクリプトではないので、その場合には、たとえ並列処理が行われる可能性があったとしても、排他を考える必要はなさそうですよね? (と、他人様に聞いてどうなるんだ。笑) また、本題からそれているので、これ以上、深追いはしないでおきますね。笑 今回も、適切なアドバイスをありがとうございました。 助かりました。

回答No.1

SQLiteはあまり使ったことがないので一般的なSQLサーバの話ですが、 もしテーブルが一つしかなく、検索の際にクラスをまたがった検索を行わないのであれば、クラスごとにテーブルを分けるのがいいでしょう。 もし、UNION等で連結させる必要があったり、別々に検索して後から結合するようであれば、初めから一つのテーブルにした方が良いと思います。頻度にもよりますが。 そのほかは、詳細なテーブル構成や使用する検索条件によって変わります。 一般的にはテーブルを分けたりすると検索は遅くなります。 正規化しても遅くなります。 ただ、正規化していないデータは管理が大変だったり、データの更新が遅くなったり、ディスクの容量がかさんでしまいますので、バランスが大事です。 後はIndexの作り方です。 Microsoftのツールなんかの場合は、データの更新は完全に正規化されたテーブルに更新し、更新が完了したらトリガー等で正規化されたテーブルからビューテーブルという検索専用に非正規化されたテーブルを更新して、検索作業はそこから行うようになっています。MS-ProjectServer等です。 後はDBはチューニングによっても大きく性能が左右されます。SQLiteがどれほどチューニングが可能かわかりませんが・・・

march4
質問者

お礼

ありがとうございました(^^) また何かありましたら、教えて下さいね。

march4
質問者

補足

早速のアドバイス、ありがとうございます。 >もし、UNION等で連結させる必要があったり、別々に検索して後から結合するようであれば、初めから一つのテーブルにした方が良いと思います。頻度にもよりますが。 テーブルを小分けしたほうが、検索するエリアを予め絞り込めるので、その方が高速な検索ができるものと思っていますが、それ自体、間違っているのでしょうか? と、疑問に思った所、 頂いたアドバイスの中に、 > 一般的にはテーブルを分けたりすると検索は遅くなります。 という一文を発見。 じゃぁ、テーブルを分ける意味って、何なのだろう。。。 という疑問がわいてきました。 (私が、その程度のDB利用者という意味でもあります。汗) >そのほかは、詳細なテーブル構成や使用する検索条件によって変わります。 ふむ。。。なるほどぉ。 >正規化しても遅くなります。 1つのカラムに盛りだくさんの情報を入れた方が、管理が大変になったり等の不便な面はありますけども、検索自体は速くなりやすいわけですね。 これは、テーブルを複数つくらず、1つのテーブルに盛りだくさんの情報を入れる方が、検索速度が高速になりやすいという話と似ていますね。 なんとなく、DBの特製が分かってきました。 データを小分けしたほうが、逆に速度は遅くなり、 逆に、1つの箱にデータを盛りだくさん詰め込んだ方が、一般的に検索速度は上がりやすいんですね。 ただ、データの更新の処理速度は遅くなるようですね。 (「データの更新が遅くなったり」というご意見を受けて。) >DBはチューニングによっても大きく性能が左右されます この辺は、まだ私には難しい話になりますが、検索速度に大きく影響するようであれば、これから勉強したいと思います。

関連するQ&A

  • SQliteの日付検索について

    SQliteの日付検索について教えてください。 現在、SQLiteでデータベースを作成しています。 日付で範囲を選択してデーターを抽出したいのですが、方法がよく分かりません。 (例:2011-08-20から2011-08-27までの日にち分のデータを抜き出したい) どなたか教えてください。 ちなみにデータベースにはDATE型でdateのcolumに”2011-08-20”という風に保存してあります。

    • ベストアンサー
    • MySQL
  • SQLiteからMySQLへの変換方法

    PHP(5.2.8)+SQLite(2.8.17)でサイトを運営しています。 データベースをMySQL(5.0.33)に変更したいと考えているのですが、 データをSQLiteからMySQLに変換するいい方法はあるでしょうか。 ちなみにSQLiteのデータの文字コードはUTF-8で、 MySQLではEUC-JPにしたいと思っています。 また、もしMySQLからSQLiteに戻す方法もあれば、 合わせて教えていただけるとうれしいです。 mt-db-convert.cgiなるスクリプトが配布されているようですが、 Movable Typeのサイトではないので、 このスクリプトが使用できるのかどうかもよく分かっていません。 何かいい方法がありましたら、ぜひご教示ください。

    • ベストアンサー
    • MySQL
  • SQLiteのデータベースについて

    PHP初心者です。以下のSQLiteより作成するデータベースについて教えてください。 $DB = sqlite_open('db1.db'); $sql="create table tables(id integer ,name,texts)"; $result=sqlite_query($db,$SQL); 上記、プログラムにより、同ディレクトリに、db1.dbが作成されますが、このデータベース情報はどのようにして、閲覧するのでしょうか(MS-ACCESS、SQLのように簡単に閲覧できないのか)。主キーやテーブルの名前またはフィールドの名前の変更、データ一覧閲覧などどのようにするのでしょうか。 環境は、Windows環境で、PHP4を使用しております。 よろしくお願いいたします。

    • ベストアンサー
    • PHP
  • SQlite

    SQLiteを使って メールを保存するデータベースを作っています。 以下のようになっています。  さらに、 アドレス帳を作りたいのですが 新たにデータベースを開くのか 同じデータベースで別のテーブルを開けばよいのかわかりません。 ご存知の方よろしくお願いします。 また、 C++からSQLiteを扱う上での参考書などもありましたら 教えてください。 rc = sqlite3_open(".\\mailbox\\SQMail.db", &db); if( rc ){ AfxMessageBox("Can't open database:", MB_OK); sqlite3_close(db); return; } rc = sqlite3_exec(db, "create table MailTbl (id INTEGER PRIMARY KEY, attach varchar(20), subject varchar(120),addressfrom varchar(80),addressto varchar(80),date varchar(80),size integer,priority integer, read integer, state integer, alldata blob);", callback, 0, &zErrMsg); if( rc!=SQLITE_OK ){ // AfxMessageBox("SQL error:", MB_OK); sqlite3_free(zErrMsg); }

  • AndroidアプリでSQLiteファイルを更新

    随時更新されるデータベース(以下DB)のAndroidアプリを作成しています。 今回はそんなに大きなDBではないので 初回起動時: assetフォルダにSQLiteファイルを用意しておく 起動時に「/data/data/[package_name]/」以下にSQLiteファイルをコピーしてDBを作成 次回起動時: DBに更新があったかチェック 更新があった場合、WEB上に用意したSQLiteファイルをHTTP通信で取得 既存のSQLiteファイル(/data/data/[package_name]/)に上書き という処理を書こうとしています。 初回起動時の処理は書けたのですが、 更新時の処理で、HTTPから取得したSQLiteデータを、どのように上書き保存したらよいのかわかりません。 処理はAsyncTask内でHTTP通信とともに行う予定です。 どなたかご教授お願いいたします。

    • ベストアンサー
    • Java
  • (PHP 4.4.8) sqlite_open関数の引数を相対パスにしたいのですが上手くいきません。

    PHP 4.4.8 SQLite Library 2.8.14 の環境で、 sqlite_open関数の引数を相対パスにしたいのですが上手くいきません。 (例)create_db.php <?php $db = sqlite_open("../db_test"); //←ここでエラーが出ます。 $query = "CREATE TABLE tbl_test(id,aaa,bbb)"; $result = sqlite_query($db,$query); sqlite_close($db); ?> ネットで調べた所、sqlite_open()は引数に「相対パス(or絶対パス)」を入れることは可能であり、 かつ、「../db_test」が無い場合、作られる仕組みということです。 エラー表示: Warning: sqlite_open() [function.sqlite-open]: unable to open database (...以下略) ちなみに、上記のコードにおいて、 「../db_test」ではなく、「db_test」として同じことをすると、上手くいきます。 つまり、スクリプトファイル(create_db.php)と同階層にファイルを作成することはできるのです。 $db = sqlite_open("db_test");   //← ○:ファイル作成成功 $db = sqlite_open("../db_test"); //← ×:ファイル作成失敗 どなたかご助言をよろしくお願い致します。

    • ベストアンサー
    • PHP
  • SQLiteのテーブルデータ移行について

    SQLiteについて質問します。 よろしくお願いします。 [環境] WindowsXP pro sp3 sqlite 3.6.9 [やりたいこと] SQLiteのテーブルのデータを、別のSQLiteのデータベースに移行したい。 ただし、移行の操作はすべてコマンドプロンプト上で実行したい。 [現状] 移行したいテーブルのデータをCSV形式でアウトプット出来ています。 [困っていること] 1.移行したいテーブルのデータに改行が入っていると、インポートに失敗してしまう。 >うまくインポートできる例 1,2,"あいうえお",5,6,2011/10/21 >インポートに失敗する例 1,2,"あいう えお",5,6,2011/10/21 2.CSVの文字列データの先頭と最後尾にある「"」も一緒にインポートされてしまう。 1,2,"あいうえお",5,6,2011/10/21 このデータをインポートした場合、 1|2|あいうえお|5|6|2011/10/21 この様にインポートしたいが、 1|2|"あいうえお"|5|6|2011/10/21 この様にインポートされてしまう。

  • SQLiteでのDateTimeの扱い

    SQLiteのデータベースにphpで値を保存したいのですが、カラムのタイプがdatetimeだと上手くいきません。 現在の時刻をSQLiteに書き込むということをしたいです。 カラムのタイプをdatetimeからtextに変更するのは避けたいので、下のphpを変更して書き込めるようにするにはどうすれば良いのでしょうか? 詳しい方よろしくお願いします。 SQLite DB ---- CREATE TABLE "dt" ("ID" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL ,"REGIST" DATETIME) ---- PHP ---- $sqlite = 'SQLiteへのパス'; $db = new PDO($sqlite); $now = date('Y-m-d H:i:s'); $nfe = $db->prepare('insert into dt(REGIST) values(?)'); $nfe->execute(array($now)); ----

  • MySQLのdbファイルの置き場所について

    MySQLのdbファイルの置き場所について 最近SQLiteからMySQLに移行しました。 しかし、とまどっています。 SQLiteだとデータベースファイルは好きな場所に置いて好きな場所から開けていました。 MySQLだとそういった任意の場所にあるデータベースファイルを開いたりすることは できないのでしょうか? mysql_connectはsqlite_openのように相対パスでどこからdbファイルを開くかの 指定ができないようだったので。

    • ベストアンサー
    • PHP
  • SQLiteに画像を格納したい

    作りたいと思っているシステムは、テキストと画像をDBに格納し、編集と削除ができるような簡単なデータベースのようなものです。 そこで、DBにはSQLiteを使おうと思っているのですが、調べてみたところSQLiteに画像を格納するのはあまりよくない(できない?ややこしい?)というような記事などを目にしました。 実際のところはどうなのか、ということをお聞きしたいです。 画像はただ単純にサーバーにアップロードするような方法が望ましいのでしょうか。 どなたかご返答頂ければと思います。 どうぞよろしくお願いいたします。

    • ベストアンサー
    • PHP