Vì lợi ích của hiệu suất và giả sử bạn đang sử dụng InnoDB, tôi có thể chuẩn hóa dữ liệu một chút, như sau:
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)
);
Mỗi cặp thành phố có 2 hàng trong CITY_DISTANCE chứa cùng một DISTANCE (một cho mỗi hướng). Điều này rõ ràng có thể làm cho nó rất lớn và có thể dẫn đến sự mâu thuẫn dữ liệu (cơ sở dữ liệu sẽ không tự bảo vệ mình khỏi các giá trị DISTANCE không khớp giữa các thành phố giống nhau) và DISTANCE về mặt logic không thuộc về PK, nhưng tôi ...
các bảng InnoDB được nhóm lại , có nghĩa là bằng cách khai báo PK theo cách cụ thể này, chúng tôi đặt toàn bộ bảng trong B-Tree đặc biệt thích hợp cho một truy vấn như sau:
SELECT CITY2_ID, DISTANCE
FROM CITY_DISTANCE
WHERE CITY1_ID = 1
ORDER BY DISTANCE
LIMIT 5
Truy vấn này trả về 5 thành phố gần nhất với thành phố được xác định bởi 1
và có thể được đáp ứng bằng cách quét phạm vi đơn giản trên B-Tree được đề cập ở trên:
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"
BTW, InnoDB sẽ tự động tạo thêm một chỉ mục (trên CITY2_ID) vì FK thứ hai, cũng sẽ bao gồm CITY1_ID và DISTANCE vì các chỉ mục phụ trong các bảng được nhóm phải bao gồm PK. Bạn có thể khai thác điều đó để tránh DISTANCE trùng lặp (tạo chỉ mục rõ ràng trên {CITY2_ID, DISTANCE, CITY1_ID} và để FK sử dụng lại nó và CHECK (CITY1_ID