26

でスピードアップselect count(*)するにはgroup by
遅すぎるため、非常に頻繁に使用されます。3,000,000 行を超えるテーブルの使用と
使用に大きな問題があります。select count(*)group by

select object_title,count(*) as hot_num   
from  relations 
where relation_title='XXXX'   
group by object_title  

relationship_titleobject_titleは varchar です。 ここで、1,000,000 を超える行を返すrelationship_title='XXXX'を使用すると、 object_titleのインデックスがうまく機能し ませんでした。

4

9 に答える 9

52

難易度の高い順に、私が試してみたいことがいくつかあります。

(より簡単) - 適切なカバリング インデックスがあることを確認してください

CREATE INDEX ix_temp ON relations (relation_title, object_title);

これにより、既存のスキーマを考慮してパフォーマンスを最大化する必要があります。これは、(mySQL のオプティマイザーのバージョンが本当に馬鹿げている場合を除きます!) クエリを満たすために必要な I/O の量を最小限に抑えるためです (インデックス全体が逆順である場合とは異なります)。スキャンする必要があります)、クエリをカバーするため、クラスター化インデックスに触れる必要はありません。

(少し難しい) - varchar フィールドができるだけ小さいことを確認してください

MySQL での varchar インデックスのパフォーマンス上の課題の 1 つは、クエリを処理するときに、フィールドの宣言されたサイズ全体が RAM に取り込まれることです。したがって、varchar(256) があり、4 文字しか使用していない場合でも、クエリの処理中に 256 バイトの RAM 使用量が発生します。痛い!したがって、varchar の制限を簡単に縮小できれば、クエリが高速化されるはずです。

(難しい) - ノーマライズ

単一の文字列値を持つ行の 30% は、別のテーブルに正規化するための明確な叫びであるため、文字列を何百万回も複製することはありません。3 つのテーブルに正規化し、整数 ID を使用してそれらを結合することを検討してください。

場合によっては、隠れて正規化し、現在のテーブルの名前と一致するビューで正規化を非表示にすることができます...その後、INSERT/UPDATE/DELETE クエリに正規化を認識させるだけで済みますが、SELECT はそのままにしておくことができます。 .

(最も難しい)-文字列列をハッシュし、ハッシュにインデックスを付けます

正規化によってコードの変更が多すぎるが、スキーマを少し変更できる場合は、( MD5 関数を使用して) 文字列列に 128 ビット ハッシュを作成することを検討することをお勧めします。この場合 (正規化とは異なり)、すべてのクエリを変更する必要はなく、INSERT と一部の SELECT のみを変更する必要があります。とにかく、文字列フィールドをハッシュしてから、ハッシュにインデックスを作成する必要があります。

CREATE INDEX ix_temp ON relations (relation_title_hash, object_title_hash);

SELECT をいじって、ハッシュ インデックスを介して計算を行い、クラスター化インデックスをプルしていないことを確認する必要があることに注意してください (クエリを満たすために object_title の実際のテキスト値を解決するために必要です)。

また、relation_title の varchar サイズが小さいが、オブジェクト タイトルのサイズが長い場合、object_title のみをハッシュして にインデックスを作成できる可能性があります(relation_title, object_title_hash)

このソリューションは、これらのフィールドの一方または両方がハッシュのサイズに比べて非常に長い場合にのみ役立つことに注意してください。

また、小文字の文字列のハッシュは大文字のハッシュと同じではないため、ハッシュによる大文字と小文字の区別/照合の興味深い影響があることにも注意してください。したがって、文字列をハッシュする前に正規化を適用する必要があります。つまり、大文字と小文字を区別しない DB にいる場合は、小文字のみをハッシュします。DB が先頭/末尾のスペースを処理する方法に応じて、先頭または末尾からスペースを削除することもできます。

于 2009-10-12T19:09:37.630 に答える
10

複合インデックスを使用して、GROUP BY 句で列のインデックスを作成することを最初に試みます。このようなクエリは、インデックス データのみを使用して回答できる可能性があり、テーブルをスキャンする必要がまったくありません。インデックス内のレコードは並べ替えられるため、DBMS はグループ処理の一部として別の並べ替えを実行する必要はありません。ただし、インデックスはテーブルの更新を遅くするため、テーブルの更新が頻繁に発生する場合は注意してください。

テーブル ストレージに InnoDB を使用する場合、テーブルの行は主キー インデックスによって物理的にクラスター化されます。それ (またはその先頭部分) がたまたま GROUP BY キーと一致する場合、関連するレコードが一緒に取得されるため、このようなクエリが高速化されるはずです。繰り返しますが、これにより、別の並べ替えを実行する必要がなくなります。

一般に、ビットマップ インデックスは別の効果的な代替手段ですが、私の知る限り、MySQL は現在これらをサポートしていません。

マテリアライズド ビューは別の可能なアプローチですが、これも MySQL で直接サポートされていません。ただし、COUNT 統計を完全に最新にする必要がない場合は、CREATE TABLE ... AS SELECT ...ステートメントを定期的に実行して結果を手動でキャッシュすることができます。これは透明ではないので少し醜いですが、あなたの場合は許容できるかもしれません。

トリガーを使用して、論理レベルのキャッシュ テーブルを維持することもできます。このテーブルには、GROUP BY 句の各列の列があり、その特定のグループ化キー値の行数を格納するためのカウント列があります。実表で行が追加または更新されるたびに、その特定のグループ化キーの集計表でカウンタ行を挿入または増分/減分します。これは、キャッシュされた要約が常に最新であり、各更新が段階的に行われ、リソースへの影響が少ないため、偽のマテリアライズド ビュー アプローチよりも優れている可能性があります。ただし、キャッシュ テーブルでのロックの競合には注意する必要があると思います。

于 2009-06-23T08:47:54.080 に答える
7

InnoDB がある場合、count(*) およびその他の集計関数はテーブル スキャンを実行します。ここにいくつかの解決策があります:

  1. トリガーを使用し、集計を別のテーブルに格納します。長所: 整合性。悪い点: 更新が遅い
  2. 処理キューを使用します。長所:更新が早い。短所: キューが処理されるまで古い状態が続く可能性があるため、ユーザーは整合性の欠如を感じる場合があります。
  3. ストレージ アクセス レイヤーを完全に分離し、集計を別のテーブルに格納します。ストレージ層はデータ構造を認識し、完全なカウントを行う代わりにデルタを適用できます。たとえば、その中に「addObject」機能を提供すると、オブジェクトがいつ追加されたかがわかるため、集計が影響を受けます。次に、update table set count = count + 1. 長所: 高速更新、整合性 (ただし、複数のクライアントが同じレコードを変更できる場合に備えて、ロックを使用することをお勧めします)。短所: 少しのビジネス ロジックとストレージを組み合わせます。
于 2009-06-24T09:00:01.927 に答える
2

何人かの方から、クエリに使用したエンジンを尋ねられたようです。次の理由で MyISAM を使用することを強くお勧めします。

InnoDB - @Sorin Mocanu は、インデックスに関係なく完全なテーブル スキャンを実行することを適切に識別しました。

MyISAM - 現在の行数を常に手元に保持します。

最後に、@justin が述べたように、適切なカバリング インデックスがあることを確認してください。

CREATE INDEX ix_temp ON relations (relation_title, object_title);
于 2009-10-12T19:23:43.687 に答える
1

count(myprimaryindexcolumn) をテストし、パフォーマンスを count(*) と比較します

于 2009-06-24T15:15:06.383 に答える
1

別のカウント テーブルを保持する必要があります。このテーブルは、挿入/削除のたびに更新できます。この種のクエリは瞬時に実行されます。

于 2020-09-29T17:48:33.747 に答える
0

より多くの RAM/CPU/IO が本当に必要になるポイントがあります。ハードウェアでそれを達成した可能性があります。

通常、テーブル内の行全体の 1 ~ 2% を超えるクエリにインデックスを使用するのは効果的ではないことに注意してください (カバーしている場合を除きます)。大規模なクエリがインデックス シークとブックマーク ルックアップを実行している場合、1 日合計クエリからのキャッシュされたプランが原因である可能性があります。WITH (INDEX=0) を追加してテーブル スキャンを強制し、高速かどうかを確認してください。

からこれを取ります: http://www.microsoft.com/communities/newsgroups/en-us/default.aspx?dg=microsoft.public.sqlserver.programming&tid=4631bab4-0104-47aa-b548-e8428073b6e6&cat=&lang=&cr= &sloc=&p=1

于 2009-06-23T08:28:53.150 に答える