MySQLのHEAPまたはMEMORYストレージエンジンを使用した場合の注意点とは?

このQ&Aのポイント
  • MySQLのキャッシュを使用したストレージエンジン、HEAPまたはMEMORYの注意点は?キャッシュを使用したランキング表示について考えています。
  • 重い処理を回避するために、HEAPまたはMEMORYストレージエンジンを使用する方法について質問です。
  • HEAPまたはMEMORYストレージエンジンを使用する際のメモリ上限や再起動によるデータ消失への注意点を教えてください。
回答を見る
  • ベストアンサー

HEAP または MEMORYについて

MySQLでのキャッシュを使用したストレージエンジン、HEAP またはMEMORYについて質問です。 あるゲームのスコアランキングを表示したいのですが、 ユーザーごとに最新のデータでのランキングとしたいので、処理が重くなりそうです。 仮にrankingテーブルとして、 sequenceID:シーケンスID(主キー) int auto increment score:得点 user:ユーザー select `user`,`score` from `ranking` where `sequenceID` in ( select `sequenceID`,`score` from `ranking` group by `user` order by max( `sequenceID`) ) order by `score` desc クエリはこんな感じで大丈夫でしょうか。。。。 このクエリ自体はためしていませんが、 とりあえず、重そうですので、HEAP または MEMORY のようなストレージエンジンを使いたいと考えています。 この場合の注意点はどういうところでしょうか。 再起動で消える、ということは承知していますので、メモリ上限にならないようにする工夫などの体験談というか、実際にMEMORYで運用されたことがある方、ぜひご助言ねがいます。

  • MySQL
  • 回答数3
  • ありがとう数1

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

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

MEMORY等を使うこと以前に、テーブル設計やインデクス設計をしっかり行った方が良いのでは? 質問中のSQLは、文法的に間違っているし、性能上も好ましくありません。 母体データ件数、ユーザ毎の平均のデータ件数は、ある程度、見積もれているのでしょうか? また、ユーザ毎のスコアの履歴を、残す必要があるのでしょうか?そういう点でもメモリ常駐する意味があるのか疑問です。

ozawachev
質問者

補足

ご助言ありがとうございます。 SQL文の文法的誤りは、 副問い合わせの 「select `sequenceID`,`score` from ...」の部分でしたでしょうか。。。 ここは「select `sequenceID` from ...」でOKでしょうか。 また、質問の趣旨とはずれますが、 こういう場合のSQL文の例など、教えていただけると幸いです。 >母体データ件数、ユーザ毎の平均のデータ件数は、ある程度、見積もれているのでしょうか? こちらですが、まだオープン前のサイトなので、目処がたっていません。 ユーザごとのスコアの履歴は残す必要があります。 MEMORYを使用したいと考えたのは、単純に高速になるかな。。という浅はかな考えからでした。 逆に、MEMORYを使用するのに適したケースというのは、どういった場合なのでしょうか?

その他の回答 (2)

回答No.3

MySQLのバージョンは何でしょうか? >調べたところ副問い合わせでは、インデックスは使えないようなことを見かけ 副問い合わせでは、「まったくインデクスを使ってくれない」ということはありません。ただ、少し試してみましたが、確かに期待したようには使ってくれない感じで、もっと試行錯誤が必要な感じです。 履歴を「取りあえず、すべて保存」ということからも、メモリ上に置くという考えはすぐに破綻してしまうかも知れません。やはり最新値と履歴で、テーブルを分けた方がいいと思います。 >普通にスコアの降順で集計したほうがいいのでしょうか? MySQLは、「昇順と降順を混在させると、インデクスを利用したソート抑止をできない」という制限事項があるので、留意して置いてください。 例えば、 create index t1ix1 on t1(c1 desc,c2 asc) といったインデクスを定義できるのですが、実際には(c1 asc,c2 asc)のインデクスが作成されます。 「order by c1 asc,c2 asc」または「order by c1 desc,c2 desc」では、このインデクスを利用できますが、「order by c1 desc,c2 asc」ではソート抑止してくれません。 これについては、マニュアルに説明があり、「show create table」でのDDL生成結果からも確認できます。 >ヒープとは無関係になってきておりますが、ご教授いただけると幸いです。 とりあえず、メモリに乗せるかどうかは棚上げにし、テーブル設計、インデクス設計、SQLの書き方に絞って再質問してはいかがでしょうか? 質問日時が古くなり、質問のタイトルからも他の人は回答に参加しにくいでしょう。 この質問のURLを貼り付け、再質問することをお勧めします。

ozawachev
質問者

お礼

アドバイス、ありがとうございます。 質問の仕方も含め、いろいろと参考になりました。 あせって聞きかじったことで対処しようとしていましたが、 ご指摘いただいた「テーブル設計、インデクス設計、SQLの書き方」これらの勉強をもっとしなければ、、、と痛感しました。 ちょっとまとめて、改めて別タイトルで再質問してみます。 ありがとうございました。

回答No.2

MySQLで実機確認する環境はないのでしょうか? >SQL文の文法的誤りは、副問い合わせの >「select `sequenceID`,`score` from ...」の部分でしたでしょうか。。。 >ここは「select `sequenceID` from ...」でOKでしょうか。 何がしたいのでしょうか? その条件部分だけでなく、group by、max関数等の使い方が正しくありません。 >こういう場合のSQL文の例など、教えていただけると幸いです 「こういう場合」とは、具体的にどういう場合ですか? たぶんやりたいのは、次のようなSQLなのでしょう。。。 select * from ranking as R where `score`=(select max(`score`) from ranking where R.`user`=`user`) order by `score` desc ※サブクエリ中に、「group by `user`」があってもいい ただ、、、 (1)得点履歴を残す理由→何に使う? (2)得点履歴を残す場合、どのタイミングで記録する? (3)得点履歴を残す場合、何世代前まで保持する? (4)得点は増えるだけ?減ることはない? など、ちょっと思いつくだけでも、これくらいの仕様の不明点があります。 インデクスは、どのように付けようと思っていますか? 仕様が不明確な状態だから、そこまで考慮されていないでしょうか? 母体データ数が数百件くらいまでなら、インデクスはなくても平気ですが、1万件、10万件となれば、適切なインデクスがないと、母体件数に比例して性能劣化します。また、group byやorder byを使う場合、適切なインデクスがないと、作業用のメモリやファイルを浪費します。 「重そうだから、MEMORYはどうか?」という、はるか以前の話です。 こんな状態でメモリに乗せようとしたら、過去何世代ものデータを持てばメモリを浪費することになるし、乗り切らないかもしれません。適切なインデクスがなければ、CPU使用率が100%近い状態が続き、ハングアップしたような状況になるかも知れません。 >MEMORYを使用するのに適したケース (1)多くの処理で必ず参照や更新するようなテーブル (2)操作は、「=」条件などで絞込みできるもの。 (3)行の長さはなるべく短く、可変長のデータ型は極力使わない。 (4)データの内容は、本当に「メモリに乗せる必要があるものだけ」にする。

ozawachev
質問者

補足

ご回答ありがとうございます。 したいことは、 「ユーザーとスコアを表示させるランキング表示」で、 ランキングはスコアの降順になります。 ユーザーのスコアは以前記録したスコアより低くても、最新のものが評価されます。 ご指摘いただいた不明点ですが、以下のようになります。 (1)得点履歴を残す理由は、後々、スコアの変遷などを見るためです。 (2)得点履歴の記録のタイミングは、ゲーム終了時です。 (3)得点履歴の保持ですが、すべて保存します。 (4)得点は減ることがあります。最新のものが反映されます。 教えていただいたSQLですが(こちらの意図を汲んでいただいてすみません。。。)、ほぼこちらで問題なくほしかった結果を取得できました。 select * from ranking as R where `sequenceID`=(select max(`sequenceID`) from ranking where R.`user`=`user`) order by `score` desc 最新のものを取得するので、 where `score`=(select max(`score`) →where `sequenceID`=(select max(`sequenceID`) と変更して、うまくいきました。 インデックスは「user」につけました。 ...ですが、EXPLAINで確認すると、userにつけたインデックスは使えていましたが、主キーのsequenceIDが使えていませんでした。 調べたところ副問い合わせでは、インデックスは使えないようなことを見かけました。 この場合は仕様上しょうがないということで、 インデックスなしのままにするしかないのでしょうか? もしくは、そもそも一つのテーブルでやろうとせず、 最新データを記録するランキングテーブルと、履歴用テーブルをつくり、 スコア記録時に、 ランキングテーブル→最新データでアップデート 履歴用テーブル→インサート とし、 ランキング集計時はランキングテーブルから 普通にスコアの降順で集計したほうがいいのでしょうか? ヒープとは無関係になってきておりますが、ご教授いただけると幸いです。

関連するQ&A

  • PHP,MySQLで3つのランキング

    前提: seisekiテーブルに id(Primary), student_id(生徒ID), kamoku_id(科目ID), score, time, created のフィールドがあります。 ランキングの順位条件は、同じ科目でscoreがより高く、timeがより短く、createdがより古い方が高位となります。 同じ科目を何度でも受講できる為、student_idはユニークではありません。 前提条件から、以下3つのランキングを取得したいと考えています。 ランキング1:科目毎のランキング(同じstudent_idが1~10位独占等可) ランキング2:自分(student_id)の全受講履歴と履歴毎のランキング ランキング3:id指定時のランキング情報 各ランキングは、1SQLである必要はなく、PHPでの加工も考慮に入れております。 試行錯誤しているのですが、ORDER BY区にどうやって順位を付ければ良いのか分からず、 SELECT * FROM seiseki ORDER BY kamoku_id DESC, score DESC, time ASC, created ASC ここから進みません・・・ 何卒、よろしくお願いいたします。

    • ベストアンサー
    • MySQL
  • 大変困っております。PHP DBにお詳しい方宜しく御願致します。

    初歩的なことかもしれません。 御助言頂きたいと思いご質問させて頂きます。 ポイントサイトを構築している途中で会員さんのポイント獲得ランキングを昇降順にDBより抽出しようと試みましたが無理でした。 こちらのソースからの後の記述が分かりません。 SELECT * FROM $k_user_table order by point DESC 結局分からぬまま最終的に以下の様にすることが精一杯でした。 ---------------------- <?php $point_count = $DB->getone("SELECT * FROM $k_user_table order by point DESC"); print $point_count; ?> ---------------------- この形でもやはり1件の獲得ポイントのみが出たり或いは一桁のちょっと訳が分からない数字が出たりします。 ポイントの高い順に10位まで表示したいと思っております。 テーブル名はこちらSELECT * FROM $k_user_table order by point DESCで間違いないはずなんですけどDBへの接続等その後のWHERE・=・<・>・等の記述方法の(~の場合~にする)の様な定義付けが分かりません。 先輩方の御助言頂けますでしょうか。 宜しく御願致します。

    • ベストアンサー
    • PHP
  • EXPLAINのUsing filesortについて

    explain select * from address where area =1 order by id desc limit 10,1\G 上記クエリーをexplainで確認すると Extra: Using where; Using filesort が表示されてしまいます。 1. Using filesortを消したいのですが、idを降順で表示するのに order by id desc 以外の方法はありますか?このような場合、Using filesortは仕方ないのでしょうか? 2. Using whereは効率の悪いクエリーの要素になるのでしょうか?

    • ベストアンサー
    • MySQL
  • sqglについて

    sqlのlimitとdescは一緒に使えますか? 例 select * from hp order by limit id 0,20 order by id desc; idを小さい順に1~20個表示したいです。

    • ベストアンサー
    • MySQL
  • mysql内データ検索結果の表示順について

    mysql内のデータを条件検索する時、検索結果の表示順を指定します。 新着順(id降順)で指定する場合のエラーについてアドバイスをいただけないでしょうか。 例えば、DB内データを降順で全件表示する場合は、 $query = "SELECT * FROM テーブル名 ORDER BY id DESC"; とすることでできると思います。 そこで、条件検索で結果表示をする場合は、上記の通りにしてもエラーが発生します。これについてのコードは以下のような感じです。 $query = "SELECT * FROM テーブル名 ORDER BY id DESC"; $where = array(); if (isset($_GET['area'])and($_GET['area'] !== '')) { $where[] = sprintf("(area='%s')", mysql_real_escape_string($_GET['area'])); } if (count($where) <> 0) { $query .= ' where ' . implode(' and ', $where); } これは、ORDER BY id DESCを書く位置が悪いのでしょうか? order by句は$query = select ~~~のあとに付けるという認識だったのですが、場合によって間違いとなるということなのでしょうか。 アドバイスをいただければ幸いです。

    • 締切済み
    • PHP
  • MySQLで最小値

    次の様な連番が入ったseqというフィールドがあります。 => select seq from hoge order by seq desc; seq ----- 427 426 425 424 423 422 421 420 419 418 (10 rows) これにlimit 5とすると次の様にな結果になります。 => select seq from hoge order by seq desc limit 5; seq ----- 427 426 425 424 423 (5 rows) このlimit 5で表示された結果の最小値(423)を取得したいのですが 上手くいきません。(わかりません) min(seq)を試してみたのですが418が返ってきてしまいます。 => select min(seq) from hoge order by seq desc limit 5; min ----- 418 (1 rows) limitで表示された結果の最小値(423)を とる事はできるのでしょうか? どうぞ宜しくお願いいたします。

    • ベストアンサー
    • MySQL
  • クエリの遅さの原因

    下記のクエリーをそれぞれ試してみたところ、圧倒的に下の方が遅くなってしまいました。 $rs = mysql_query("select * from A INNER JOIN B ON B.cat = A.id order by B.id desc LIMIT 1, 10 ;",$con); $rs = mysql_query("select * from A INNER JOIN B ON B.cat = A.id where B.name is not null group by B.area order by B.id desc LIMIT 1, 10 ;",$con); where B.name is not null group by B.area この処理はそれほど負荷が掛かってしまうのでしょうか。 他に良い書き方(方法)がありましたら教えてください。

    • ベストアンサー
    • MySQL
  • order byで並び変えし最大値の項目の抽出方法ついて

    すみません。 order byで並び変えし最大値の項目のみ一意で抽出したいのですが 、 SELECT * from ta order by no,date1,date2; no | date1 | date2 ----+-------+------- 11 | 2008 | 0501 11 | 2008 | 0502 11 | 2008 | 0502 11 | 2008 | 0503 12 | 2008 | 0501 12 | 2008 | 0502 12 | 2008 | 0503 13 | 2008 | 0501 13 | 2008 | 0502 13 | 2008 | 0503 14 | 2008 | 0501 とあった場合、 no,date1,date2のorder by順番で並び変えし 11 | 2008 | 0503 12 | 2008 | 0503 13 | 2008 | 0503 14 | 2008 | 0501 とno項目に対し一つずつだけ出力したい場合どのようにしたらよいのでしょうか? LIMITとoffsetだと1項目分しか出力されず困っております。 SELECT * from ta where no in (select no from ta group by no limit 1 offset 0) order by no,date1 desc,date2 desc limit 1; 宜しくお願い致します。

  • 秀丸でSQLを書く際に SQLの予約語だけ大文字

    秀丸でSQLを書く際に SQLの予約語だけを、大文字に変換するよい方法は? たとえば select * from table_1 where id=1 order by id desc; と書いて、マクロを起動すると SELECT * FROM talbe_1 WHERE id=1 ORDER BY id DESC; となるようにするよい方法はありませんか? また、予約語が「強調」されると尚良いです。

  • 【添削願】クエリ文、エラーが改善できません。

    こちらのPHPがうまく出力されません。 自分なりに書いてますが なかなか間違いを見つけられず添削お願いできると ありがたいです。 最初の4行のサーバー名はダミーです $sv = "mysql.xxx.jp"; $dbname = "bbb"; $user = "bbb"; $pass = "aaa"; $link = mysqli_connect($sv, $user, $pass,$dbname); $editpagename ="main"; $query = "SELECT * FROM $editpagename ORDER BY id DESC LIMIT 0 , 50"; $result = mysqli_query($link, $query); var_dump($result); どのようなことが考えられるでしょうか? よろしくお願い致します。

    • ベストアンサー
    • PHP