パフォーマンスのために、そしてあなたがInnoDBを使用していると仮定すると、私はおそらく次のようにデータを少し非正規化するでしょう:
CREATE TABLE CITY (
CITY_ID INT PRIMARY KEY
);
CREATE TABLE CITY_DISTANCE (
CITY1_ID INT,
CITY2_ID INT,
DISTANCE NUMERIC NOT NULL,
PRIMARY KEY (CITY1_ID, DISTANCE, CITY2_ID),
FOREIGN KEY (CITY1_ID) REFERENCES CITY (CITY_ID),
FOREIGN KEY (CITY2_ID) REFERENCES CITY (CITY_ID)
);
都市の各ペアには、同じDISTANCEを含むCITY_DISTANCEの2つの行があります(各方向に1つ)。これは明らかにそれを非常に大きくし、データの不整合につながる可能性があり(データベースは同じ都市間で一致しないDISTANCE値からそれ自体を防御しません)、DISTANCEは論理的にPKに属していませんが、私に耐えてください...
InnoDBテーブルはクラスター化されています 、つまり、この特定の方法でPKを宣言することにより、テーブル全体を次のようなクエリに特に適したBツリーに配置します。
SELECT CITY2_ID, DISTANCE
FROM CITY_DISTANCE
WHERE CITY1_ID = 1
ORDER BY DISTANCE
LIMIT 5
このクエリは、1
で識別される都市に最も近い5つの都市を返します。 、および上記のBツリーでの単純な範囲スキャンで満たすことができます:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE CITY_DISTANCE ref PRIMARY PRIMARY 4 const 6 "Using where; Using index"
ところで、クラスター化テーブルのセカンダリインデックスはPKをカバーする必要があるため、InnoDBは2番目のFKのために(CITY2_ID上に)もう1つのインデックスを自動的に作成します。これにはCITY1_IDとDISTANCEも含まれます。これを利用して、重複するDISTANCEを回避できる場合があります({CITY2_ID、DISTANCE、CITY1_ID}に明示的にインデックスを作成し、FKに再利用させ、(CITY1_ID