Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Speichern einer Entfernungsmatrix in DB

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