5

MySql データベースに基づいて PyQT ソフトウェアを開発しています。データベースには、いくつかの記録された電気信号と、これらの信号を説明するすべての情報 (サンプリング レート、記録の日付など...) が含まれています。

アイデアを得るために、1 つのデータベースに 10,000 ~ 100,000 行が含まれ、合計サイズが 10Gb を超えるとします。これらのデータはすべて専用サーバーに保存されます。実際、ほとんどのデータは信号自体であり、analogsignal.signal という BLOB フィールドにあります (以下を参照)。

データベースのアーキテクチャは次のとおりです: http://packages.python.org/OpenElectrophy/_images/simple_diagram1.png

変更できません (列とインデックスを追加できますが、既存の列を移動または削除することはできません)。

ソフトウェアでは、analogsignal.id を介して後で呼び出される analogsignal.signal を除いて、すべての analogsignal 列 (id、名前、チャネル、t_start、sampling_rate) をリストする必要があります。だから私は次のクエリをやっています

SELECT block.id、block.datetime、segment.id、analogsignal.id、analogsignal.name、analogsignal.channel、analogsignal.sampling_rate、block.fileOrigin、block.info

FROM セグメント、ブロック、アナログ信号

WHERE block.id=segment.id_block

AND segment.id=analogsignal.id_segment

ORDER BY analogsignal.id

問題は、analogsignal.signal 列が存在するため、クエリが非常に遅いことです (リクエストがキャッシュにない場合は 10 分以上)。何が起こっているのかを正しく理解していれば、analogsignal.signal が SELECT フィールドにない場合でも、analogsignal.signal を含むテーブルが 1 行ずつ読み取られます。

BLOBを他のテーブルに移動せずにデータベースまたはクエリを最適化する方法を知っている人はいますか(これはより論理的であることに同意しますが、この点は制御しません)。

ありがとうございました!

これは、AnalogSignal テーブルの CREATE TABLE コマンドです (コメントからプル/フォーマットされています)。

CREATE TABLE analogsignal 
  ( id int(11) NOT NULL AUTO_INCREMENT, 
    id_segment int(11) DEFAULT NULL,
    id_recordingpoint int(11) DEFAULT NULL, 
    name text, 
    channel int(11) DEFAULT NULL, 
    t_start float DEFAULT NULL, 
    sampling_rate float DEFAULT NULL, 
    signal_shape varchar(128) DEFAULT NULL, 
    signal_dtype varchar(128) DEFAULT NULL, 
    signal_blob longblob, Tag text, 
    PRIMARY KEY (id), 
    KEY ix_analogsignal_id_recordingpoint (id_recordingpoint),
    KEY ix_analogsignal_id_segment (id_segment) 
  ) ENGINE=MyISAM AUTO_INCREMENT=34798 DEFAULT CHARSET=latin1 ;

編集:問題は解決しました。重要な点は次のとおりです。

-アナログ信号テーブルのすべての SELECT フィールドに複数列インデックス、タイプ INDEX を追加する必要がありました
。 - 「TEXT」タイプの列がインデックスの使用をブロックしていました。これらの TEXT フィールドを VARCHAR(xx) に変換しました。このために、次の簡単なコマンドを使用しました。

SELECT MAX(LENGTH(field_to_query)) FROM table_to_query

変換前に最小テキスト長をチェックして、データが失われないことを確認する

ALTER TABLE table_to_query CHANGE field_to_query field_to_query VARCHAR(24)

最初は VARCHAR(8000) を使っていたのですが、この設定だと VARCHAR が TEXT フィールドみたいになり、インデックスが効かなくなりました。VARCHAR(24) ではそのような問題はありません。私が正しければ、クエリの TEXT の合計長 (すべてのフィールドを含む) は 1000 バイトを超えてはなりません

次に、上記のようにすべての列にインデックスを付けました。インデックスにサイズパラメーターはありません

最後に、より優れたクエリ構造を使用して (DRapp に感謝)、クエリも改善されました。キャッシュなしで、クエリの 215 秒から 0.016 秒に渡しました...

4

4 に答える 4

4

データを外部の物理ファイルに配置し、パス\ファイル名を対応するレコードに保存するだけで、「ブロブ」列の要件を縮小しようとすることに加えて、代替手段として次のことを試します...

クエリを逆にして、AnalogSignal テーブルを最初に配置します。これは order by 句の基礎であり、クエリを逆方向にブロックに戻します。また、データのすべてのリテラル行を読み取る必要がないようにするために、出力に必要なすべての列に複合インデックスを作成すると、より大きなインデックスが作成されますが、クエリはキー式ではなく、キー式から直接値を取得します。データの実際の行への読み取りから。

AnalogSignal にインデックス KeyDataOnly を作成します (id、id_segment、name、channel、sampling_rate)

SELECT STRAIGHT_JOIN
      block.id, 
      block.datetime, 
      segment.id, 
      analogsignal.id, 
      analogsignal.name, 
      analogsignal.channel, 
      analogsignal.sampling_rate, 
      block.fileOrigin, 
      block.info
   FROM 
      analogsignal
         JOIN Segment
            on analogsignal.id_segment = segment.id
            JOIN block
               on segment.id_block = block.id
   ORDER BY 
      analogsignal.id
于 2012-11-08T13:58:10.380 に答える
1

したがって、コメントによると、あなたの問題はMyISAMストレージエンジンとデータの保存時の動作が原因であると確信しています。toxicate20は正しいです。MySQLはとにかくそれらの大きなブロブをスキップする必要がありますが、これは効果的ではありません。この問題で大いに役立つInnoDBのストレージエンジンを変更できます。SELECT ...部分で明示的に要求した場合にのみ、BLOBデータを読み取ります。

ALTER TABLE analogsignal ENGINE=InnoDB;

これにはしばらく時間がかかりますが、パフォーマンスに大いに役立ちます。InnoDBファイル形式の詳細については、次を参照してください。

http://dev.mysql.com/doc/innodb/1.1/en/innodb-row-format-antelope.html http://dev.mysql.com/doc/innodb/1.1/en/innodb-row-format -dynamic.html

免責事項:テーブルのいずれかの列で全文検索(MATCH ... AGAINST http://dev.mysql.com/doc/refman/5.5/en//fulltext-search.html)を使用する場合、それを変更することはできません。 InnoDBに。

于 2012-11-08T14:43:08.607 に答える
1

BLOB 列を削除できない場合は、埋める必要がありますか? シグナルのパス/宛先/ファイル名を格納するための列を追加し、すべてのシグナル ファイルを適切なディレクトリに配置できます。それが完了したら、BLOB フィールドの値を null に設定します。

それはおそらく、あなたが下にある制限の精神を壊しています. しかし、恣意的な制限はしばしば回避する必要があります。

于 2012-11-08T13:49:31.957 に答える
0

アナログ信号列は非常に大きいため、選択クエリを実行するときにそれらをスキップする (比喩的に見るとそれらを飛び越える) 必要があるため、クエリに時間がかかります。私がすることは次のとおりです。データベースにブロブを作成する代わりに、次の方法でバイナリ ファイルを生成します。

$fh = fopen("analogfile.spec", 'w') or die("can't open file");
$data = $yourAnalogDataFromSomewhere;
fwrite($fh, $data);
fclose($fh);

ファイル名は、たとえば列の ID によって指定されます。BLOB の代わりに、サーバー ディレクトリ構造内にファイルパスを追加するだけです。

この方法では、BLOB 列の大きなデータ チャンクをスキップする必要がないため、クエリが非常に高速に実行されます。

于 2012-11-08T13:43:03.460 に答える