PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Mehrdimensionales Array in Datenbank speichern:relational oder mehrdimensional?

Wenn das alles ist, was Sie brauchen, können Sie eine LIKE-Suche verwenden

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

Mit einem Index beginnend mit CELL Dies ist eine Bereichsprüfung, die schnell ist.

Wenn Ihre Daten nicht so aussehen, können Sie einen path erstellen Spalte, die wie ein Verzeichnispfad aussieht und alle Knoten "auf dem Weg/Pfad" von der Wurzel bis zum Element enthält.

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

Um alle Nachkommen von 'AE' (einschließlich sich selbst) abzurufen, wäre Ihre Abfrage

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

oder (MySQL-spezifische Verkettung)

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

Ergebnis:

| 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

Leistung

Ich habe 100.000 Zeilen mit gefälschten Daten auf MariaDB erstellt mit dem sequence plugin mit dem folgenden Skript:

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.

Tests

Alle Elemente unter der Wurzel zählen:

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

Unterstrukturelemente unter einem bestimmten Knoten abrufen:

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

Ergebnis:

| 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

Dies funktioniert auch für PostgreSQL. Nur die String-Verkettungssyntax muss geändert werden:

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

Demo: sqlfiddle - rextester

Wie funktioniert die Suche

Wenn Sie sich das Testbeispiel ansehen, sehen Sie, dass alle Pfade im Ergebnis mit „1/4/11/14/614/4284/“ beginnen. Das ist der Pfad der Teilbaumwurzel mit CELL='3B0' . Wenn der path Spalte indiziert ist, findet die Engine sie alle effizient, da der Index nach path sortiert ist . Es ist, als ob Sie in einem Wörterbuch mit 100.000 Wörtern alle Wörter finden möchten, die mit „pol“ beginnen. Sie müssten nicht das gesamte Wörterbuch lesen.