複合(concept, attrib, value, business_key)
インデックスを追加して、クエリ(MySQLがこのインデックスを使用することを決定した場合)がテーブル全体を読み取ることなくインデックス内のすべての情報を見つけることができるようにすることができます。
クエリは次と同等です。
SELECT DISTINCT business_key
FROM Memory
WHERE NOT (concept = 'case' AND attrib = 'status' AND value = 'closed')
そしてこれに(おそらく同じ実行計画が得られるでしょう):
SELECT business_key
FROM Memory
WHERE NOT (concept = 'case' AND attrib = 'status' AND value = 'closed')
GROUP BY business_key
インデックスに配置される4つの列はすべてVARCHAR(255)
であるため、インデックスの長さはかなり長くなります。MyISAMは1000バイトを超えてはならず、InnoDBは3072を超えてはなりません。
1つの解決策は、最後の部分の長さをカットして、インデックスの長さを1000未満にすることです255+255+255+230 = 995
。
(concept, attrib, value, business_key(220))
それは機能しますが、パフォーマンスの観点から、インデックスの長さがこれほど長くなるのは実際には良くありません。
もう1つのオプションは、そこに格納する予定のデータに準拠している場合は、これら4つの列のすべてまたは一部の長さを短くすることです。列に255
最大値があると予想される場合は、長さを宣言する必要はありません。100
検討できるもう1つのオプションは、これらの4つの列を4つの個別の参照テーブルに配置することです。(または、データが繰り返されている列だけです。business_key
データが重複しているように見えますが、それほど多くはありません。したがって、その列の参照テーブルを作成するのはあまり良いことではありません。)
例:concept
次のような値を新しいテーブルに配置します。
CREATE TABLE Concept_Ref
( concept_id INT AUTO_INCREMENT
, concept VARCHAR(255)
, PRIMARY KEY concept_id
, UNIQUE INDEX concept_idx (concept)
) ;
INSERT INTO Concept_Ref
( concept )
SELECT DISTINCT
concept
FROM
Memory ;
Memory
次に、次のようにテーブルを変更します。
ALTER TABLE Memory
ADD COLUMN concept_id INT ;
これを行う(1回):
UPDATE
Memory m
JOIN
Concept_Ref c
ON c.concept = m.concept
SET m.concept_id = c.concept_id
Memory.concept
次に、列を削除します。
ALTER TABLE Memory
DROP COLUMN concept ;
FOREIGN KEY
テーブルをMyISAMからInnoDBに変更する場合は、参照を追加することもできます。
4つの列すべてに対して同じことを行うと、テーブル内の新しい複合インデックスの長さMemory
がはるかに短くなるだけでなく、テーブルのサイズもはるかに小さくなります。さらに、これらの列のいずれかを使用する他のインデックスの長さは短くなります。
もちろん、クエリを作成するには4つのJOINが必要です。また、このテーブルのINSERT
、UPDATE
またはDELETE
ステートメントは、変更して慎重に設計する必要があります。
しかし、全体として、パフォーマンスは向上すると思います。'case'
あなたが今持っているデザインでは、のような値が何度も繰り返されている'status'
ようです。'closed'