Aus Gründen der Leistung und unter der Annahme, dass Sie InnoDB verwenden, würde ich die Daten wahrscheinlich ein wenig denormalisieren, etwa so:
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)
);
Jedes Städtepaar hat 2 Zeilen in CITY_DISTANCE, die dieselbe DISTANCE enthalten (eine für jede Richtung). Dies könnte es offensichtlich sehr groß machen und zu Dateninkonsistenzen führen (die Datenbank wird sich nicht gegen nicht übereinstimmende DISTANCE-Werte zwischen denselben Städten wehren), und die DISTANCE gehört logischerweise nicht zum PK, aber ertragen Sie mich ...
InnoDB-Tabellen sind geclustert , was bedeutet, dass wir durch die Deklaration des PK auf diese besondere Weise die gesamte Tabelle in einem B-Baum ablegen, der sich besonders für eine Abfrage wie diese eignet:
SELECT CITY2_ID, DISTANCE
FROM CITY_DISTANCE
WHERE CITY1_ID = 1
ORDER BY DISTANCE
LIMIT 5
Diese Abfrage gibt die 5 Städte zurück, die der durch 1
identifizierten Stadt am nächsten liegen , und kann durch einen einfachen Bereichsscan auf dem oben erwähnten B-Baum erfüllt werden:
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"
Übrigens erstellt InnoDB aufgrund des zweiten FK automatisch einen weiteren Index (auf CITY2_ID), der auch CITY1_ID und DISTANCE enthält, da sekundäre Indizes in gruppierten Tabellen PK abdecken müssen. Sie können dies möglicherweise ausnutzen, um doppelte Entfernungen zu vermeiden (erstellen Sie explizit einen Index für {CITY2_ID, DISTANCE, CITY1_ID} und lassen Sie ihn von FK wiederverwenden, und prüfen Sie (CITY1_ID