次のような非常に大きなルックアップテーブルがあるとします。
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の行が何回発生したかを教えてくれます。
a
:INDEX(something, time)
でWHERE
を満たしますMyLookup
-(FKToTableA, FKToTableB)
のペアが一意の場合は、そのPRIMARY KEY
を作成し、SELECT
がMyLookup
にすばやくアクセスできるように列をその順序で配置します。BIGINT
(8バイト)は使用しないでください。これは、INT UNSIGNED
の制限であり、4バイトしかかかりません。INT UNSIGNED
に変換するための便利なルーチンがあります。新しいIPv6では、BIGINT
には適合しません。 5.6.3を参照してください。SUMs
からJOINing
の前にb
を実行します。この設計は、ログデータを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を選択します。また、アプリケーションを変更できる場合は、さらに最適化を行うことができます。
b.something
_を選択してから、すべてのSQLクエリを同時に実行します。 CPUリソースをより効率的に使用します。