PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Memorizza l'array multidimensionale nel database:relazionale o multidimensionale?

Se questo è tutto ciò di cui hai bisogno, puoi utilizzare una ricerca LIKE

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

Con un indice che inizia con CELL questo è un controllo della portata, che è veloce.

Se i tuoi dati non sono così, puoi creare un path colonna che assomiglia a un percorso di directory e contiene tutti i nodi "sulla strada/percorso" dalla radice all'elemento.

| 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/ |

Per recuperare tutti i discendenti di "AE" (incluso se stesso) la tua richiesta sarebbe

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

o (concatenazione specifica per MySQL)

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

Risultato:

| 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

Prestazioni

Ho creato 100.000 righe di dati falsi su MariaDB con il plug-in sequenza utilizzando il seguente script:

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.

Prove

Conta tutti gli elementi sotto la radice:

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

Ottieni elementi di sottoalbero in un nodo specifico:

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

Risultato:

| 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

Funziona anche per PostgreSQL. È necessario modificare solo la sintassi di concatenazione delle stringhe:

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

Demo: sqlfiddle - rextester

Come funziona la ricerca

Se guardi l'esempio di test, vedrai che tutti i percorsi nel risultato iniziano con '1/4/11/14/614/4284/'. Questo è il percorso della radice del sottoalbero con CELL='3B0' . Se il path colonna è indicizzata, il motore li troverà tutti in modo efficiente, perché l'indice è ordinato per path . È come se volessi trovare tutte le parole che iniziano con 'pol' in un dizionario con 100.000 parole. Non avresti bisogno di leggere l'intero dizionario.