web-dev-qa-db-ja.com

MySQL-ルックアップテーブルの最適なインデックス。 HASHインデックス、BTREEインデックス、または複合PK?

次のような非常に大きなルックアップテーブルがあるとします。

   CREATE TABLE `MyLookup` (
      `FKToTableA` bigint(20) NOT NULL,
      `FKToTableB` bigint(20) NOT NULL,
      `Count` bigint(20) NOT NULL,
      `Bytes` bigint(20) NOT NULL,
      `Packets` bigint (20) NOT NULL,
   ) ENGINE=InnoDB;

最初の2つの属性は、それぞれテーブルAおよびBに対するFKです。しかし、そうである必要はありません。 FKを持たない方が最適な場合は、FKを削除できます。 FKToTableAおよびFKToTableBは、このテーブルの候補キーです。したがって、FKToTableAとFKToTableBは、必要に応じて複合主キーになる可能性があります。

私の質問は、このテーブルにインデックスを付ける最も最適な方法は何ですか?ストレージサイズと挿入時間は問題ではありません。ほとんどの場合、私のクエリは両方のFK列でMyLookupに参加し、SUM、Count、Bytes、およびPackets列で結合します。

select
    a.something, b.something, SUM(c.Count), SUM(c.Bytes), SUM(b.Packets)
from
    A a 
    inner join MyLookup c on a.Id = c.FKToTableA
    inner join B b on b.Id = c.FKToTableB
where
    a.something = 1 and
    a.Time >= 'blah' and
    a.Time <= 'blah'
group by 
    a.something, b.something

3つのオプションが表示されます。

1)FKToTableAおよびFKToTableBにHASHインデックスを配置します。

2)すべての列に複合BTREEインデックスを配置します。

3)FKToTableAおよびFKToTableBに主キーを配置します。

私は1に少し傾いています。私が収集したものから、HASHインデックスは等価比較で優れており、すべての結合が大きな等価比較であるということではありませんか?それでもボトルネックになる可能性がありますが、他の列を合計するには、再びテーブルにアクセスする必要があります。わからない。

それとも、Count、Bytes、Packetsのハッシュインデックスを持つことが可能ですか?ただし、複合ハッシュインデックスがどのように機能するかはわかりません。

誰かが以前にこの種のことを扱ったことがあり、いくつかの知識と提案を捨てることができますか?

編集:これをもう少し明確にするために、テーブルAとBの私のスキーマです

CREATE TABLE `B` (
  `Id` bigint(20) NOT NULL AUTO_INCREMENT,
  `CustomerIdent` int(11) NOT NULL,
  `MetaData1` varchar(256) NULL,
  `MetaData2` varchar(256) NULL,
  `MetaData3` varchar(256) NULL,
  `MetaData4` varchar(256) NULL,
  `MetaData5` varchar(256) NULL,
  `Time` datetime NOT NULL
  CONSTRAINT `PK_A` PRIMARY KEY (`Id` ASC)
) ENGINE=InnoDB;

CREATE TABLE `B` (
  `Id` bigint(20) NOT NULL AUTO_INCREMENT,
  `SourceIp` bigint(20) NULL,
  `DestinationIp` bigint(20) NULL,
  `SourcePort` int(11) NULL,
  `DestinationPort` int(11) NULL,
  CONSTRAINT `PK_B` PRIMARY KEY (`Id` ASC)
) ENGINE=InnoDB;

基本的に、ルックアップテーブルは、Aの1つの行に対してBの行が何回発生したかを教えてくれます。

2
mBrice1024
  • aINDEX(something, time)WHEREを満たします
  • MyLookup-(FKToTableA, FKToTableB)のペアが一意の場合は、そのPRIMARY KEYを作成し、SELECTMyLookupにすばやくアクセスできるように列をその順序で配置します。
  • 40億を超えると予想される場合を除き、BIGINT(8バイト)は使用しないでください。これは、INT UNSIGNEDの制限であり、4バイトしかかかりません。
  • IPアドレス-古いIPv4の場合、INT UNSIGNEDに変換するための便利なルーチンがあります。新しいIPv6では、BIGINTには適合しません。 5.6.3を参照してください。
  • それらのメタデータ列にはutf8が必要ですか?それらをTEXT列に結合できますか?そして他の質問。
  • この「レポート」を取得するために、「ファクト」テーブルの大きなチャンクをスキャンするのではなく、「サマリーテーブル」を作成して維持します。
  • SUMsからJOINingの前にbを実行します。
  • 本当に多対多のマッピングテーブルが必要ですか?このように見えます1:多く。
  • 多対多 に関するその他のヒント。
1
Rick James

この設計は、ログデータをMySQLに保存したようであり、分析を行いたいと考えています。

Cassandra(またはScyllaDB、CassandraのC++で書き換えられた互換性のあるソリューション)+ Prestoを参照することをお勧めします。これらはすべてオープンソースソフトウェアであり、SQLクエリを並行して処理できます。効果的に。

特に、PrestoのSQL言語はMySQLと非常に似ているため(最初はFacebookによって開発されたため)、非常に簡単に学ぶことができます。

とにかく、InnoDBを使用する必要がある場合は、このSQLクエリに対して行う必要があるサーバー最適化があります。

  • SELECTのコードにより常に_a.something_になるため、_GROUP BY_部分の_a.something_を削除し、WHERE部分の_1_を_1_に変更します。
  • A条件のため、テーブルWHEREは_(something, Time)_または_(something, Time, ...)_にインデックスを作成する必要があります。 MyISAMを使用する場合は、範囲検索条件のため、BTREEを選択します。
  • ただし、MyISAMからInnoDBに変更することをお勧めします。InnoDBはクラッシュセーフエンジンであり、Oracleはそれを改善するために多くの努力を続けています。

また、アプリケーションを変更できる場合は、さらに最適化を行うことができます。

  • 指定された時間内にすべての可能な_b.something_を選択してから、すべてのSQLクエリを同時に実行します。 CPUリソースをより効率的に使用します。
0
Gea-Suan Lin