В името на производителността и ако приемем, че използвате 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)
);
Всяка двойка градове има 2 реда в CITY_DISTANCE, съдържащи едно и също DISTANCE (по един за всяка посока). Това очевидно може да го направи много голям и може да доведе до несъответствия в данните (базата данни няма да се защити от несъвпадащи стойности на DISTANCE между едни и същи градове), а DISTANCE логично не принадлежи към PK, но имайте търпение...
InnoDB таблиците са групирани , което означава, че като декларираме PK по този конкретен начин, ние поставяме цялата таблица в B-Tree, което е особено подходящо за заявка като тази:
SELECT CITY2_ID, DISTANCE
FROM CITY_DISTANCE
WHERE CITY1_ID = 1
ORDER BY DISTANCE
LIMIT 5
Тази заявка връща най-близките 5 града до града, идентифициран с 1
, и може да бъде удовлетворен чрез просто сканиране на обхват на 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"
Между другото, InnoDB автоматично ще създаде още един индекс (на CITY2_ID) поради втория FK, който също ще включва CITY1_ID и DISTANCE, тъй като вторичните индекси в клъстерираните таблици трябва да покриват PK. Може да успеете да използвате това, за да избегнете дублирани DISTANCE (изрично създайте индекс на {CITY2_ID, DISTANCE, CITY1_ID} и оставете FK да го използва повторно и ПРОВЕРЕТЕ (CITY1_ID