PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Lưu trữ mảng đa chiều trong cơ sở dữ liệu:quan hệ hay đa chiều?

Nếu đó là tất cả những gì bạn cần, bạn có thể sử dụng tìm kiếm LIKE

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

Với chỉ mục bắt đầu bằng CELL đây là một kiểm tra phạm vi, nhanh chóng.

Nếu dữ liệu của bạn không giống như vậy, bạn có thể tạo path cột trông giống như một đường dẫn thư mục và chứa tất cả các nút "trên đường / đường dẫn" từ gốc đến phần tử.

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

Để truy xuất tất cả các hậu duệ của 'AE' (bao gồm cả chính nó), truy vấn của bạn sẽ là

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

hoặc (nối cụ thể của MySQL)

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

Kết quả:

| 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

Hiệu suất

Tôi đã tạo 100 nghìn hàng dữ liệu giả trên MariaDB với plugin trình tự sử dụng tập lệnh sau:

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.

Kiểm tra

Đếm tất cả các phần tử dưới gốc:

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

Nhận các phần tử của cây con trong một nút cụ thể:

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

Kết quả:

| 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

Điều này cũng hoạt động cho PostgreSQL. Chỉ cú pháp nối chuỗi phải được thay đổi:

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

Bản trình diễn: sqlfiddle - trình sắp xếp lại

Tìm kiếm hoạt động như thế nào

Nếu bạn nhìn vào ví dụ thử nghiệm, bạn sẽ thấy rằng tất cả các đường dẫn trong kết quả đều bắt đầu bằng '1/4/11/14/614/4284 /'. Đó là đường dẫn của gốc cây con với CELL='3B0' . Nếu path được lập chỉ mục, công cụ sẽ tìm thấy tất cả chúng một cách hiệu quả, vì chỉ mục được sắp xếp theo path . Nó giống như bạn muốn tìm tất cả các từ bắt đầu bằng 'pol' trong một từ điển với 100 nghìn từ. Bạn không cần phải đọc toàn bộ từ điển.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Về tính hữu dụng của các chỉ mục biểu thức

  2. Tôi nên chọn loại dấu thời gian nào trong cơ sở dữ liệu PostgreSQL?

  3. Làm thế nào để tính ngày sinh tiếp theo cho một ngày sinh?

  4. SQLAlchemy - trạng thái đếm là đúng

  5. Postgres:chọn tổng các giá trị rồi tính tổng lại