PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Przechowuj tablicę wielowymiarową w bazie danych:relacyjną czy wielowymiarową?

Jeśli to wszystko, czego potrzebujesz, możesz użyć wyszukiwania LIKE

SELECT *
FROM Table1
WHERE CELL LIKE 'AEE%';

Z indeksem zaczynającym się od CELL to jest szybkie sprawdzenie zasięgu.

Jeśli Twoje dane tak nie wyglądają, możesz utworzyć path kolumna, która wygląda jak ścieżka do katalogu i zawiera wszystkie węzły "na drodze/ścieżce" od katalogu głównego do elementu.

| id | CELL | parent_id | path     |
|====|======|===========|==========|
|  1 | A    |      NULL | 1/       |
|  2 | AA   |         1 | 1/2/     |
|  3 | AAA  |         2 | 1/2/3/   |
|  4 | AAC  |         2 | 1/2/4/   |
|  5 | AB   |         1 | 1/5/     |
|  6 | AE   |         1 | 1/6/     | 
|  7 | AEA  |         6 | 1/6/7/   |
|  8 | AEE  |         6 | 1/6/8/   |
|  9 | AEEB |         8 | 1/6/8/9/ |

Aby pobrać wszystkich potomków „AE” (włącznie z nim samym), Twoje zapytanie będzie

SELECT *
FROM tree t
WHERE path LIKE '1/6/%';

lub (konkatenacja specyficzna dla MySQL)

SELECT t.*
FROM tree t
CROSS JOIN tree r -- root
WHERE r.CELL = 'AE'
  AND t.path LIKE CONCAT(r.path, '%');

Wynik:

| id | CELL | parent_id |     path |
|====|======|===========|==========|
|  6 | AE   |         1 | 1/6/     |
|  7 | AEA  |         6 | 1/6/7/   |
|  8 | AEE  |         6 | 1/6/8/   |
|  9 | AEEB |         8 | 1/6/8/9/ |

Demo

Wydajność

Utworzyłem 100 tys. wierszy fałszywych danych na MariaDB z wtyczką sekwencji za pomocą następującego skryptu:

drop table if exists tree;
CREATE TABLE tree (
  `id` int primary key,
  `CELL` varchar(50),
  `parent_id` int,
  `path` varchar(255),
  unique index (`CELL`),
  unique index (`path`)
);

DROP TRIGGER IF EXISTS `tree_after_insert`;
DELIMITER //
CREATE TRIGGER `tree_after_insert` BEFORE INSERT ON `tree` FOR EACH ROW BEGIN
    if new.id = 1 then
        set new.path := '1/';
    else    
        set new.path := concat((
            select path from tree where id = new.parent_id
        ), new.id, '/');
    end if;
END//
DELIMITER ;

insert into tree
    select seq as id
        , conv(seq, 10, 36) as CELL
        , case 
            when seq = 1 then null
            else floor(rand(1) * (seq-1)) + 1 
        end as parent_id
        , null as path
    from seq_1_to_100000
;
DROP TRIGGER IF EXISTS `tree_after_insert`;
-- runtime ~ 4 sec.

Testy

Policz wszystkie elementy pod korzeniem:

SELECT count(*)
FROM tree t
CROSS JOIN tree r -- root
WHERE r.CELL = '1'
  AND t.path LIKE CONCAT(r.path, '%');
-- result: 100000
-- runtime: ~ 30 ms

Pobierz elementy poddrzewa w określonym węźle:

SELECT t.*
FROM tree t
CROSS JOIN tree r -- root
WHERE r.CELL = '3B0'
  AND t.path LIKE CONCAT(r.path, '%');
-- runtime: ~ 30 ms

Wynik:

| id    | CELL | parent_id | path                                |
|=======|======|===========|=====================================|
|  4284 | 3B0  |       614 | 1/4/11/14/614/4284/                 |
|  6560 | 528  |      4284 | 1/4/11/14/614/4284/6560/            |
|  8054 | 67Q  |      6560 | 1/4/11/14/614/4284/6560/8054/       |
| 14358 | B2U  |      6560 | 1/4/11/14/614/4284/6560/14358/      |
| 51911 | 141Z |      4284 | 1/4/11/14/614/4284/51911/           |
| 55695 | 16Z3 |      4284 | 1/4/11/14/614/4284/55695/           |
| 80172 | 1PV0 |      8054 | 1/4/11/14/614/4284/6560/8054/80172/ |
| 87101 | 1V7H |     51911 | 1/4/11/14/614/4284/51911/87101/     |

PostgreSQL

Działa to również dla PostgreSQL. Należy zmienić tylko składnię konkatenacji ciągów:

SELECT t.*
FROM tree t
CROSS JOIN tree r -- root
WHERE r.CELL = 'AE'
  AND t.path LIKE r.path || '%';

Demo: sqlfiddle - rextester

Jak działa wyszukiwanie

Jeśli spojrzysz na przykład testowy, zobaczysz, że wszystkie ścieżki w wyniku zaczynają się od „1/4/11/14/614/4284/”. To jest ścieżka do korzenia poddrzewa z CELL='3B0' . Jeśli path kolumna jest indeksowana, silnik znajdzie je wszystkie sprawnie, ponieważ indeks jest posortowany według path . To tak, jakbyś chciał znaleźć wszystkie słowa zaczynające się od „pol” w słowniku zawierającym 100 000 słów. Nie musisz czytać całego słownika.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Najlepsze praktyki w zakresie replikacji PostgreSQL — część 2

  2. Błąd rejestru PostgreSQL pg_ctl pod Windows 7

  3. Utwórz diagram ER w pgAdmin

  4. Wskazówki dotyczące wdrażania PostgreSQL w chmurze hybrydowej

  5. Procedura wyzwalania Postgresa przy wstawianiu wykorzystująca dane we wstawionych polach do wstawienia obliczonych danych w innym polu