sql >> Databáze >  >> RDS >> Mysql

Uložení matice vzdáleností v DB

Kvůli výkonu a za předpokladu, že používáte InnoDB, bych pravděpodobně data trochu denormalizoval, například takto:

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)
);

Každá dvojice měst má 2 řádky v CITY_DISTANCE obsahující stejnou DISTANCE (jeden pro každý směr). Tím by to samozřejmě mohlo být velmi velké a mohlo by to vést k nekonzistentnostem dat (databáze se nebude bránit proti neshodným hodnotám DISTANCE mezi stejnými městy) a DISTANCE logicky nepatří do PK, ale mějte se mnou...

Tabulky InnoDB jsou seskupené , což znamená, že deklarováním PK tímto konkrétním způsobem vložíme celou tabulku do B-stromu, který je zvláště vhodný pro dotaz, jako je tento:

SELECT CITY2_ID, DISTANCE
FROM CITY_DISTANCE
WHERE CITY1_ID = 1
ORDER BY DISTANCE
LIMIT 5

Tento dotaz vrátí 5 měst nejblíže k městu označenému 1 , a může být uspokojen jednoduchým skenováním rozsahu na B-stromu zmíněném výše:

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 automaticky vytvoří jeden další index (na CITY2_ID) kvůli druhému FK, který bude zahrnovat také CITY1_ID a DISTANCE, protože sekundární indexy v klastrovaných tabulkách musí pokrývat PK. Můžete toho být schopni využít, abyste se vyhnuli duplicitním vzdálenostem (explicitně vytvořte index na {CITY2_ID, DISTANCE, CITY1_ID} a nechte jej FK znovu použít, a CHECK (CITY1_ID

  1. MySQL se nepřipojuje v cmd

  2. Aktualizace pomocí poddotazu v MySQL

  3. Odstraňte duplikáty pomocí funkce Oracle LISTAGG

  4. Doctrine 2 QueryBuilder přidat více vybraných prvků/parametrů?