-1

私は、多くの同時軽量SQLクエリを作成する必要のあるアプリケーションを持っています。たとえば、ユニットクエリは「このストアでは、今日カテゴリ別に販売のリストを提供してください」のようなものです。このクエリは非常に安価で、数十ミリ秒で実行されます。並行軽量SQLクエリを高速化

このクエリは、店舗レベルで実行する必要があります。「このストアグループのすべてのトランザクション(約30まで)で、今日のカテゴリ別の販売リストを提供してください。これは明らかに、グループ内のストアセットに対する結合として実装可能ですが、これは遅すぎます。これは、取引の数に比例して減速します(実際には、買ったアイテムの合計数に比例して)。

代わりに、ストアレベルの並行クエリを多数実装しました(バッチサイズを実際のものに変更しました)。その結果をアプリケーションレイヤにマージします。これは、特にPreparedStatementsと組み合わされた場合に、うまく機能します。残念ながら、これは十分に速くはありません。これは、大半の時間は5〜15秒から0.5〜1.5秒のクエリ時間を要しますが、3秒かかることがあります。許容範囲外(2秒未満)です。

許容されるキャッシング時間枠内で同じクエリが実行される可能性は低いため、情報はキャッシュ可能ではありません。最近の過去(2週間程度)のクエリは非常に迅速に実行されることに注意してください.DBが書き込みを行うと、DB/OSキャッシュにそのデータの新しさが保持されます。それはキラーですランダムな読み取りです。

DBウィザードには、このクエリ処理のスピードアップのヒントがありますか?私は非常にSQLに慣れていて、私のオフィスの誰もこれほど前にこのようなことを試していません。私はベンチマークを行い、それらを非常に徹底的にタイムアウトしました。これは、同時に100回のクエリ(30 * 3のメトリック+いくつかのより簡単なクエリ)のスピンオフであり、同時にコストがかかります。クエリ時間のリストは[10, 15, 30, 55, 89, 100, 300, ..., 1599]のようになり、すべて​​コールの周りにのみ時間が設定されます。参考までに私はC3P0と500-1000のオープンDB接続とAmazon AuroraをDBとしてアプリケーション言語としてJavaを使用しています。私は2つの読み取り - 複製の間で100のクエリをロード・バランシングしようとしましたが、これは名目上パフォーマンスを改善するだけのようです。私はTRANSACTION_READ_UNCOMMITTEDSCROLL_INSENSITIVE + READ_ONLYから少しパフォーマンスが向上していると思います。

編集:一部のテーブル構造とクエリ(Pardonの名前transaction - 私は実際にこの名前を使用しませんが、ビジネス上の理由から変更しました。)

CREATE TABLE IF NOT EXISTS item ( item_id BIGINT UNSIGNED AUTO_INCREMENT, item_name VARCHAR(120), unit_price DECIMAL (10,2), PRIMARY KEY (item_id) ) ENGINE=INNODB;

CREATE TABLE IF NOT EXISTS transaction_item_list ( ticket_transaction_id BIGINT UNSIGNED AUTO_INCREMENT, transaction_id BIGINT UNSIGNED, item_id BIGINT UNSIGNED, item_quantity DECIMAL(10,2), item_sales DECIMAL(10,2), FOREIGN KEY (item_id) REFERENCES item (item_id), FOREIGN KEY (transaction_id) REFERENCES transaction (transaction_id), PRIMARY KEY (transaction_item_id) ) ENGINE=INNODB;

CREATE INDEX transaction_id_idx ON transaction_item_list (transaction_id);

CREATE INDEX item_id_idx ON transaction_item_list (item_id);

CREATE TABLE IF NOT EXISTS transaction ( transaction_id BIGINT UNSIGNED AUTO_INCREMENT, native_transaction_id VARCHAR(36) NOT NULL, store_id BIGINT UNSIGNED NOT NULL, server_time DATETIME NOT NULL, business_date DATE NOT NULL, FOREIGN KEY (store_id) REFERENCES store (store_id), PRIMARY KEY (transaction_id) ) ENGINE=INNODB;

# used for insertion

# used for querying CREATE UNIQUE INDEX store_date_transaction_id_idx ON ticket (store_id, business_date, transaction_id);

CREATE INDEX store_id_idx ON transaction (store_id);

CREATE INDEX date_idx ON transaction (business_date);

CREATE INDEX server_time_idx ON transaction (server_time);

SELECT sum(transaction_item_list.item_quantity * item.unit_price) FROM transaction_item_list JOIN item USING (item_id) JOIN transaction USING (transaction_id) WHERE (transaction.store_id, transaction.transaction_date) IN ((?, ?)) GROUP BY category;

transaction_item_listテーブルは、データの1年分100万700以上の行があります。

+0

テーブル構造といくつかのサンプルクエリを提供してください。 –

+0

@MohamedYasinが追加されました。 –

+0

関連するテーブルに 'SHOW CREATE TABLE'を指定してください(あなたの説明は十分詳細ではありません)。 –

答えて

0

この構造体は使用しないでください。WHERE (store_id, transaction_date) IN ((?, ?));それは貧弱に最適化されます。代わりに、テーブル名(またはエイリアス)とJOINで述べた各列を修飾してください

WHERE store_id = ? 
    AND transaction_date = ? 

を使用します。読者(私たち)がどこから来ているのか把握するのは面倒です。必要

インデックス:多くのマッピング(プラス余分な列):

transaction: INDEX(store_id, transaction_date) -- in that order 
transaction_item_list: INDEX(transaction_id) -- if not already there 

transaction_item_list多くのようなにおいがします。もしそうなら、私の7 tips on many:manyを見てください。

+0

私はこれら両方のインデックスを持っています - 実際には '(store_id、transaction_date、) 'のインデックスを(その順番で)持っていて、MySQLは最初の11ビット程度しか使っていません。 –

+0

そして 'IN((?、?))'が実際に最適化されている大きなテーブルのバグについて聞いたことがありますか?どのようにしてその最適化が悪いのか、なぜその理由が推奨されていますか? –

+0

データベース設定に表示されるテーブル定義とインデックス作成を追加しました。 「USING」を伴う結合は、両方のテーブルで列名が同じであることを意味します。 –

関連する問題