SQLiteで構築した商品管理ツールのデータベースをMySQLに変更するべきか悩んでいます

このQ&Aのポイント
  • 現在、PHP+pdo+SQLiteで構築している商品管理ツールのデータベースをMySQLに変更するべきか悩んでおり、セキュリティや同時書き込みの問題などを考慮しています。
  • SQLiteは同時書き込みでデータベースがロックしてしまうため、複数人での運用が難しいです。一方、MySQLは難易度が高く、時間がかかります。
  • PHP側でSQLiteのデータベースへの同時書き込みを無くす工夫をすれば運用上は問題なさそうですが、セキュリティに不安があります。データベースはルートより上に置くことを考えています。
回答を見る
  • ベストアンサー

MySQLは難易度が高いのでSQLiteで構築

お世話になります。 現在Web上で動作する商品管理のツールをPHP+pdo+MySQLでデータベースを構築しています。 MySQLでの構築は初めてで、いろいろ手間がかかっています。 今まではPHP+pdo+SQLiteでデータベースを構築していました。 しかし同時書き込みでデータベースがロックしてしまうSQLiteの仕様では複数人数での運用ができません。 そこでMySQLに変更しようと思ったのですが、いろいろ覚えることが多くて時間がかかってしまっています。 やはりSQLiteの構築のしやすさは魅力的です。 そこで、MySQLでの構築を一旦中止し、SQLiteで構築しようかと思っています。 PHP側で工夫してSQLiteのデータベースへの同時書き込みを無くせば運用的には問題なさそうでしょうか? セキュリティ的に不安ですがデータベースはルートより上に置きます。 助言があればお願い致します。

  • suffre
  • お礼率76% (2013/2633)

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

  • ベストアンサー
回答No.3

正直、書いてあることからどういうデザインなのか今ひとつピンときません。 普通、ロックによる性能劣化の解消方法はロックの粒度を細粒度にするか、ロックフリーアルゴリズムの採用だと思いますが、提案されている方法はどちらでもないように思います。 > DBに書き込み前にロック用ファイルをファイルロックをし、書き込みが終わったらロックを解除する、という感じです。 というデザインにしたことでどうして現状より良くなるんでしょうか? これはSQLiteがロックしてくれていたところを自分でやっただけで、本質的に現状と変わらないと思います。むしろ、自分の実装ミスによってロックがされず、にデータの消失や不整合を招くリスクのほうが高いのではないでしょうか。 いや、RESERVEDやPENDINGといったSQLite3のロック状態を使えない分だけ、それをちゃんと使って書いたコードよりも、ロックの粒度は粗くなっているので、トータルでの性能は落ちそうです。 質問者が言うところのロックファイルを使う実装というのは、要はすべてEXCLUSIVEにするということですよね? ちなみに、 http://www.sqlite.org/lockingv3.html によると、SQLite3からはPENDING状態があることでリードの多発によってEXCLUSIVEロックが取れない状態というのは解消されたそうです。 > その他に、メインのDBに書き込みできるのはマスターのPHPだけにして、ユーザーは一切書き込みできないようにする、という方法です。 ロックを取る話と今ひとつつながって見えませんが、普通に考えていくつも問題が思い浮かびます。 1. DBの内容の不整合 2. スレーブ?によって新規作成されたDBファイル名の競合 3. スレーブ?によって新規作成されたDBが書き込み中であったことによるマスターの待ち 4. スレーブ?によって新規作成されたDBファイルによるディスク領域の圧迫 1についてですが、例えば、持っている商品の数に整合性がないわけですから、ヘタしたら自分が持っている数以上に商品を出してしまいますよね。商品数が1個で、ユーザーAもユーザーBもそれを使えると思って確保したら、マスターが突き合わせをした時に不足しているとわかると。 あるいは、新規商品の追加だけしかしないとしたら、同一商品の追加があった時に微妙に内容が違っていたことでエントリーが複数できたりしませんか?また、登録したものがマスターが処理を終えるまで見られないという状況になるとも思います。 2について、被らないようにファイル名をつけないと、先の入力を後の入力で上書きしそうです。あるいは、マスターによるDBの削除でデータがあるファイルを削除しそうです。 3について、1分ごとにマスターのデータベースを止めてひたすらアップデートをするので、スレーブ?が作ったファイルが著しく多かったり、スレーブ?が自分が書いているDBのロックを取ったまま帰らないことが多かったりすると、その間マスターを使えないということになりませんか? 4について、それぞれのスレーブがDBファイルを作るとなると、書き込みが増えれば増えるほどファイルのオーバーヘッドの部分によるディスク領域の圧迫もありそうです。 > しかし同時書き込みでデータベースがロックしてしまうSQLiteの仕様では複数人数での運用ができません。 一応確認ですが、書き込みにはちゃんとトランザクションを使っていますよね。使うのと使わないのとでは雲泥の性能差がSQLite2のころからあるようですが。 http://www.sqlite.org/speed.html あと、釈迦に説法だと思うのですが、インデックスをちゃんと設定してquery planも確認してますよね。 http://www.sqlite.org/eqp.html http://www.sqlite.org/queryplanner.html それでだめならMySQLの採用もやむなしだと思うのですが。 自分だったらSQLite3でちゃんと性能が出るように実装してみて、ダメだったらもっと細かい粒度でロックが取れるRDBMSを採用するというアプローチを取るでしょう。 #1さんと同じく、ロック機構を自分で実装するというのは、リスクが高すぎてやりたくないです。

suffre
質問者

お礼

アドバイス頂きましてありがとうございます。 確かに自前でロックファイルを作るのはやはり無理ですよね…。ちょっと安易に考えていたようです。 あと、「メインのDBに書き込みできるのはマスターのPHPだけにして…」というのはロックファイルの件とは別の方法ということです。なのでロックを取る話とは関係ないです。 1についてですが、マスターが処理を終えるまでメインのデータベースから商品を参照できないのは許せる範囲と思っています。 ユーザーAとBにはそれぞれ専用のデータベースを作る予定です。 同一商品の追加があったときに内容が微妙に違うのは織り込み済みで、エントリーは複数できないようにします。 2は問題ないと思っています。「先の入力を後の入力で上書きしそう」というのもそれは上書きして問題ありません。 3ですが、一度に登録できる商品数に制限を入れているので問題ない範囲かと思っています。 4ですが、スレーブが作るDBのファイル数にも上限を入れようと思っています。 >一応確認ですが、書き込みにはちゃんとトランザクションを使っていますよね。 SQLite3ですが、自分の環境で複数プロセスで同時書き込みを行ったところ、データベースファイルがロックされたままの状態になってしまい、以後そのデータベースファイルが使えなくなってしまった経験があります。トランザクションは使用していました。 ネットで調べたところ、このデータベースファイルをコピーしたものを再利用することでロックから解放されるとありましたのでそのようにして対処しました。 トランザクションのやり方が間違っていたのか、もう一度確認してみようと思います。

その他の回答 (2)

  • mitoneko
  • ベストアンサー率58% (469/798)
回答No.2

 No.1です。  まぁ、一番単純な形での実装ですね。  ロックの手法としても一番単純な形ですから、マルチスレッドにおけるロックの実装を体験するには良い題材かもしれません。  もし、マルチスレッドでの共有資源のロックを組むのが初めてでしたら、「言うは簡単、するは・・・」であることは覚悟しておいてください。  もし、マルチスレッドのロックを作成したことがあるなら、以下は、無視してもらって結構です。  注意ポイントはひとつです。「ロックファイルの存在を確認する」「ロックファイルを生成する」という一連の作業は、アトミックな(分離不可分な)処理ではありません。この処理中に他のプロセスは任意のタイミングで割り込む可能性があります。  どういう意味かというと、単純な例を挙げれば、  プロセスA:ロックファイルが無いことを確認した。  プロセスB:ロックファイルが無いことを確認した。  プロセスA:ロックファイルを作成した。  プロセスB:ロックファイルを作成した(踏みつぶした???)  プロセスA及びプロセスB:共有リソースの使用で喧嘩をしながら処理を続行・・・・  なんてことが絶対に発生しないようにロジックを組む必要があります。(この単純なパターンであれば、プロセスBがロックファイルを踏みつぶす時点でエラーとすることも出来るかもしれません。)  「ロックファイルの存在確認」も、「ロックファイルの生成」も、両方ともアトミックな処理では無いことにも注意が必要です。ロックファイルの生成中にも、ロックファイルの存在確認が発生する可能性があると言うことです。  また、DBへのアクセスが完全にシリアライズされますから、効率は・・・・まぁ、言及する必要は無いですよね。  最初に一番単純と書きましたが、結構難しいですから、頑張ってください。  ポイントは、自分の書いている一連の手順同士が割り込みあったら何が起きるかを徹底的に考えることです。一つの行で書いた処理が(ないしは一つの単語で書いた処理が)、中断されない処理であることを当てにしてはいけません。(極端な話、「変数Aをインクリメントする」処理でさえアトミックではないのです。インクリメントしている途中に・・・という事態は現実に発生します。)  一般的には、クリティカルセクションを特定し、セマフォやスピンロックなどで実装するのが普通です。このあたりの用語で調べてみると良いでしょう。

suffre
質問者

お礼

再度のアドバイス、ありがとうございます。 ロックファイルはファイルに書き込みをするときに必ず使っているので使用経験はあります。 ただ、自分が使っているロック方法ではロック用ファイルは最初から存在した状態です。 確かに単純にロックファイルというのもいろいろ課題があるのは承知です。 いろいろロックに関するサイトを読んでいて頭が痛くなる話が多いです。 そもそもSQLiteでもトランザクションはあるので、本来は自前でロックする必要はないはずですがそれをやらないといけないのはファイルベースのSQLiteの限界ということで、これを自分で完璧に代用するのは無理な気もします。 そうすると最初のお礼で書いたように、メインのデータベースへ書き込みするのはマスター側のPHPにして、ユーザーは書き込めないようにする、という方法のほうが安全かもしれません。 もちろんリアルタイムにデータベースに書き込みはできないですが、運用上は問題ないレベルです。

  • mitoneko
  • ベストアンサー率58% (469/798)
回答No.1

 あっさりと回答してしまうなら、私なら、たとえMySQLがどんなに面倒でも、意地でもMySQLを学習しますね。  マルチスレッドにおけるリソースの衝突管理は難しいです。ましてや、トランザクションを白紙から全部自分で構築する・・・なんてなったら、気が遠くなります。  これって、実際に作るのも恐ろしく難易度は高いんですが、作るだけなら何とかなります。でも、デバッグは出来ません。なぜなら、全てのパターンを論理的に網羅してというのが、不可能だからです。スレッドのタイミングなんてランダムですから、実験が出来ません。一日や2日程度、ちょっと何人かで走らしてみて問題が無かったら・・・なんて甘いテストなら出来ますけどね。問題が発生した時、どこが問題なのかを探すのも極めて難しい分野です。テストして問題があることが解っても、どこが問題なのかを見つける有効なツールはありません。(ちなみに、マーフィーの法則という証明はされていない真理によると、このような甘いテストをしていると、あなたが、一番トラブルが起こって欲しくないタイミングで、バグが顕在化するそうです(笑))  こんな作業するくらいなら、全ての構築作業を中断してMySQLのマニュアルを熟読してマスターした方がよっぽど楽です。

suffre
質問者

お礼

ありがとうございます。 いずれMySQLに移行できるようにPDOで作成しております。 Webツールを作る時間があまりないので今回はSQLiteで行こうかと思っていますが、同時アクセスを回避する方法は、ファイルロックと同じ要領で良いかなと考えているのですがどうでしょうか? DBに書き込み前にロック用ファイルをファイルロックをし、書き込みが終わったらロックを解除する、という感じです。 他のプロセスがDBに書き込みするときはロックファイルを監視し、ロック中ならループして解除されるまで待ちます。 その他に、メインのDBに書き込みできるのはマスターのPHPだけにして、ユーザーは一切書き込みできないようにする、という方法です。 ユーザーが何かデータを作ったら、そのデータを新規DBとして登録します。他のユーザーも何かデータを作ったら新規DBを作ります。 どんどんDBが出来上がっていきますが、マスターのPHPがその作られたDB群をメインのDBにコピーします。コピーが終わればコピー元のDBを削除します。 マスターのPHPは1分置きにcronで実行します。 こんな感じを検討しています。 もちろんMySQLにすれば良いのでしょうが、私個人で独学でやっていくしかなく、時間もあまりないためにSQLiteを検討しています。もちろんいずれはMySQLに移行したいと考えています。 再度助言があればよろしくお願い致します。

関連するQ&A

  • MySQL又はSQLiteについて

    お世話になります。 Androidアプリ開発でPHPファイルを読み込み、更にMySQLへ接続してデータベースの中身を反映させるとこまでは成功しました。 しかし、Androidアプリとデータベースの連携で調べると、SQLiteを推奨しているサイトや書籍が多いのですが、軽量のファイルベースで手軽に構築・運用できるという点は、何となくイメージできるのですが、MySQLに比べてSQLiteが明らかに優れている点はあるのでしょうか? 私は、8割方PHPでwebコンテンツの開発を行ってきました。そしてデータベースは100%MySQLを利用してきました。Androidアプリ開発を開始したのは、つい最近の事でSQLiteも今まで殆ど触れていませんでしたので、特にMySQLとSQLiteでメリット・デメリットの大差が無いのであれば、触りなれているMySQLを選択しようと考えています。 因みに、iOSアプリについては別の者が開発しています。 最終的には、AndroidとiOS両方の端末が1つのデータベースへ読みに行く構想ですので、もしiOSの開発側で、SQLiteの方が圧倒的に優れているとなれば話は変わってきますが・・・。 MySQLとSQLiteを比較して、SQLiteが優れている点のアドバイスをいただければ幸いです。 何卒、どうぞよろしくお願い申し上げます。

  • 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
  • 泣きそうです>< PHPでSQLite3が使えない

    こんばんは 何をどうやっても進まないのでここで質問させてください。 Windows 8にwamp (Apache 2.2.22, PHP 5.4.3) を入れています。 SQLite3を使いたいのですが、sqlite_open 関数に対して「undefined function」というエラーが出てしまいます。 php.ini の内容は次のようになっています。 ;ここから extension_dir = "c:/wamp/bin/php/php5.4.3/ext/" (中略) extension=php_pdo_sqlite.dll ;extension=php_sqlite.dll extension=php_sqlite3.dll (中略) [sqlite] ; http://php.net/sqlite.assoc-case ;sqlite.assoc_case = 0 [sqlite3] sqlite3.extension_dir = "c:/wamp/bin/php/php5.4.3/ext/" ;ここまで 実際、エクステンションディレクトリには php_pdo_sqlite.dll php_sqlite.dll php_sqlite3.dll があります。 phpinfo(); では PDO drivers:mysql, sqlite SQLite Library:3.7.7.1 [sqlite3] SQLite3 support:enabled SQLite3 module version:0.7 SQLite Library:3.7.7.1 sqlite3.extension_dir:c:/wamp/bin/php/php5.4.3/ext/ いったい何が行けないのでしょうか、iniの値を変えるとphpinfo()も変わるので誤った設定ファイルをいじっているのではないと思います。 バージョンなどは冒頭に記載しています。 よろしくお願いします。

  • LAMPでシステムを構築しています。

    LAMPでシステムを構築しています。 データベースサーバは2台でMySQL-Cluster-gpl-7.0.9(RPM)で構成。 2台とも想定どおりの稼動をしています。 このデータベースにPHP(ZendFrameWork)を用いてアクセスを試みたところアクセスできませんでした。 調査の結果、接続ドライバとしてPDOを使用していうことがわかり、モジュールを導入するべく php-mysqlパッケージをインストールしたいのですが、mysqlと依存関係がある上、 mysqlはMySQL-Clusterと競合してしまいます。 そこで知恵をお借りしたいのですが、接続ドライバにPDOを用いた場合、どうすれば MySQL-Clusterで構築されたデータベースにアクセスできるようになるでしょうか。 PDOに限らず同じphp-mysqlパッケージに含まれるmysql_connect()も同様の結果になります。 おそらく同じ原因だと思われます。 データベースサーバは2台、これと同じサーバにWEBサーバ(Apache)が乗っています。 以下必須条件 OS: CentOS 5.3 AP: PHP(ZendFrameWork) DB: MySQL-Cluster 変更できる点 パッケージの導入手段(tarからコンパイルでも、RPMで導入でも)。 よろしくお願いします。

  • PHP5.26でPDO(MySQL)が設定できません

    設定を確認しましたがphpinfo()のPDOの欄がno valueのままです。 PDOを使おうとすると"could not find driver"となります。 PHPのセットアップ時に選択するようになっていたので、 それ以外は何もしていないと思います。 --------------------------------------------------- 環境:Windows/PHP5.26/Apache2.28/MySQL5.0 ■php.ini内 [PHP_PDO] extension=php_pdo.dll [PHP_PDO_MYSQL] extension=php_pdo_mysql.dll [PHP_MYSQL] extension=php_mysql.dll extension_dir ="C:\Program Files\PHP\ext" ■"C:\Program Files\PHP\ext"内 php_pdo_mysql.dll php_pdo.dll php_pdo_mysql.dll 試しにセットアップで全てのDB用のPDOを選択すると、「odbc, sqlite, user」のみ 表示されるようになりました。。 よろしくお願いします。

    • ベストアンサー
    • PHP
  • PHPを始めるにあたって質問です。

    よろしくお願いします。 PHPを始めてみようかと思い、簡単な物をPHP5でPDOからMySQLを使って初めて書いて、 ローカル(XP + xampp と vmware上の ubuntu )では一応動いたのですが、 あるレンタルサーバーでは、PHP4.4.6でPDOが使えない様子で、 別なサーバーではPHP5.2.3なんですが、PDOのドライバがSQLiteしか使えないようでした。 そんなこんなで、お聞きしたいのですが、 PHPでデータベースを使った小規模なアプリケーションを書いて、レンタルサーバーで動かす場合に 無難というか、環境がそろいやすいというか、移植しやすい組み合わせというのがあれば教えて下さい。 例えば、 PHP5 + PDO + SQLite とか PHP4 + PEAR::DB + MySQL よろしくお願いします。

    • 締切済み
    • PHP
  • mysqlについてサンプルなど教えてもらえませんか

    すいません。今phpなどを使いウェブサイトを作っているのですが、データベースがどうしても 必要となり、参考サイトなどを見ながら作りました。 ほとんどできたのですが、最後に一部データベースの関数などでわからない事があり困っています。 (正直私はプログラムはphp程度が少し分かる程度で、データベースも単純な使い方しかしない 予定なので参考サイトをざっと見ただけでmysqlの事がほとんど分かりません) ググってそれらしい物を探してはいるのですが、私がやりたい事はデータベースから 件数を取りたいだけです。 取った件数をphpで表示したいのですが、何時間やっても良くわかりません。 申し訳ないんですが取り出した後その件数をphpのechoで表示するまでをサンプルとして書いてもらえませんか?(可能であれば「ここでこのような処理が行われている」とコメントがもらえると助かります) データベース関係はphpと違って初心者用のサイトなども無く、書いてある事がほとんど分かりません。 (ここでSELECT COUNT(*)を使うと教えてもらったのですが、SELECT COUNT(*)でググっても サンプルなども出てきません) $pdo = new PDO("mysql:dbname=aaa", "root"); $pdo->query("set names utf8;"); // ------------------------------------------------ $sql = $pdo->query("SELECT COUNT(*) FROM bbb"); $stmt = $pdo->query($sql); $stmt->execute(); $count=$stmt->rowCount(); echo $count; ----------------------------------------------- $result = mysql_query("SELECT COUNT(*) FROM bbb"); $row = mysql_fetch_assoc( $result ); echo $row;

    • ベストアンサー
    • MySQL
  • PHP5でSQLiteが接続エラーを出します

    PHPには初心者です(データベースには多少知識有るはず)。 PHPからSQLに商品データを登録するシステムを作っていますが、データベースに接続することができません。 繋げるためにはどこを直したらよいでしょうか。 データベース名はshop、テーブル名はitemです。 SQLite:バージョン 2.8.17 PHP:バージョン 5.1.6 WindowsXPのプロフェッショナル、eclipse3.2、参考にした本は『eclipseではじめるPHP(http://item.rakuten.co.jp/book/4296315/)』と『基礎PHP(http://item.rakuten.co.jp/book/1711777/)』です。 エラーが出る行 if(!$db = sqlite_open('/../SQLiteManager/shop')){ die("データベース接続エラー.<br/>"); } エラー文 Warning: sqlite_open() [function.sqlite-open]: unable to open database: C:\SQLiteManager\shop in C:\Eclipse\workspace\shop\touroku.php on line 23 データベース接続エラー. PHPのフォルダ内にある 『PHP.iniextension=php_pdo_sqlite.dll』 『extension=php_sqlite.dll』 のコロンは外しました。 SQLiteManagerはworkspaceの中です。 設定が悪いのかファイルを置く場所が悪いのか、それともプログラムが悪いのかもわかりません。 宜しくお願いいたします。

    • 締切済み
    • PHP
  • PHP5からSQLite3の接続

    いつもお世話になります。 現在PHPを勉強しているのですが、 PHP5からSQLite3へ接続するさいに以下のメッセージが表示されます。 Warning: sqlite_open() [function.sqlite-open]: file is encrypted or is not a database in [PHPのファイルパス].php on line 32 SQLiteのテストデータベースに接続が上手くいきません 32行目↓ $dbHandle = sqlite_open('C:/pg/Apache/Apache2.2/htdocs/testdb', 0666, $err); [環境] WindowxXP PHP Version 5.3.5 SQLite3 php_pdo.dll が../php/extフォルダーに無いのでphp.iniのコメントは外してません。 ;を外したらアパッチ起動時に「モジュールがない」と言われ起動しません。 初心者で色々調べたのですが・・・ すみませんがどなたかご教示お願い致します。

    • ベストアンサー
    • PHP
  • 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)); ----