如何對所有列都需要索引的數據進行建模?
我有以下案例,其中有一堆相互映射的 ID (GUID)。我需要查找給定任何單個 ID 的所有 ID。例如,假設我的數據具有以下列:
uid, id1, id2, id3, id4, id5
如何支持以下查詢:
1. SELECT uid FROM table WHERE id1=x; 2. SELECT id1, id2, id3, id4 FROM table WHERE uid=xyz;
ID 的數量可以更改(我必須添加新列)。
我可以在所有列上創建索引,但這不是很有效。我應該對這些數據進行不同的建模嗎?是否有任何 NoSQL 數據庫可以幫助為這個案例建模?
為了清晰起見,提供更多業務上下文,我們有來自多個數據源的數據,這些數據源具有自己的 custom_id。但它們都標識同一個人 (UID)。這就是為什麼我們需要將所有數據源 ID 映射到我們自己的內部 UID。因此問題。
- 列數的最大界限為 20-25。
- 它們可以為空。
- 每行的 id 數量可以不同(這就是為什麼可以為空)。
- 所有的數據類型都是 STRING。
- UID 將是主鍵。
您可以將表建模為具有兩列的字典:
- 使用者標識符
- ID_VALUE
兩者都將使用專用索引進行索引。
然後,您可以為任何 UID 添加盡可能多的 ID_VALUE 行並蒐索給定 ID_VALUE 的 UID。
然後查詢看起來像
SELECT UID FROM table WHERE ID_VALUE=x; SELECT ID_VALUE FROM table WHERE UID=xyz;
第二個查詢將返回不止一行。
編輯
我需要查找給定任何單個 id 的所有 id
只要您的所有 ID 都由一個公共列綁定,在本例中為 UID,這應該是可能的。考慮以下查詢:
SELECT t2.id_value FROM table t1 ,table t2 WHERE t1.uid = t2.uid AND t1.id_value = x
這將返回給定單個 id X 的所有 id。
ID_VALUE 的值是多少並不重要。它們可能是指向這個或任何其他任意數字的其他 UID。如果您想搜尋包括 UID 值的任何 ID_VALUE,您也可以將此 UID 值包含到集合中,這樣您將有一行 UID = ID_VALUE。
例子
假設您的模型中有以下數據:
UID ID1 ID2 ID3 -------------------- 1 2 3 4 2 1 4 3 4 4 2 3
您可以像這樣在字典表中對此數據進行建模:
UID ID_VALUE -------------- 1 2 1 3 1 4 2 1 2 4 3 4 4 2 4 3
如果您想在列表中包含 UID,那麼我範例中的最後一個查詢將返回包括 UID 在內的所有 ID,那麼您將擁有:
UID ID_VALUE -------------- 1 2 1 3 1 4 1 1 <--- 2 1 2 4 2 2 <--- 3 4 3 3 <--- 4 2 4 3 4 4 <---
我已標記為滿足此要求而添加的行。執行查詢:
SELECT t2.uid ,t2.id_value FROM table t1 ,table t2 WHERE t1.uid = t2.uid AND t1.id_value = 1
將導致:
UID ID_VALUE -------------- 1 2 1 3 1 4 1 1 2 1 2 4 2 2
這將根據要求返回給定任何單個 ID 的所有 ID。請注意,在 UID = 1 和 UID = 2 的兩個集合中都可以找到 ID_VALUE 為 1,兩者都返回。
這相當於在您的平面設計上執行此查詢:
SELECT * FROM table WHERE UID=1 OR ID1=1 OR ID2=1 OR ID3=1
在這種情況下,數組似乎很合適:
create table t1 ( uid varchar(50) not null primary key, alternate_ids varchar(50)[] ); insert into t1 (uid, alternate_ids) values ('one', array['eno', 'noe']), ('two', array['owt', 'tow', 'wto']), ('three', null);
查詢表:
SELECT uid FROM t1 WHERE 'eno' = any(alternate_ids); SELECT alternate_ids FROM t1 WHERE uid = 'one';
查找包含兩個特定備用 ID 的行:
SELECT uid FROM t1 WHERE alternate_ids @> array['owt', 'wto']::varchar[];
uid --- two
(注意:
::varchar[]
如果列聲明為 ,則不需要強制轉換text[]
)查找包含任何備用 ID 的行:
SELECT uid FROM t1 WHERE alternate_ids && array['owt', 'noe'];
uid --- one two
該數組可以被索引,這使得使用
@>
and&&
運算符查找備用 ID 非常有效:我用一百萬行填寫了上表。每個都有 1 到 20 個值的隨機數組。
以下查詢從該表返回大約 10000 行(共 100 萬行)
select * from t1 where alternate_ids @> array['42'];
執行計劃是:
Bitmap Heap Scan on t1 (cost=47.13..9624.00 rows=10567 width=115) (actual time=5.872..14.894 rows=10635 loops=1) Recheck Cond: (alternate_ids @> '{42}'::text[]) Heap Blocks: exact=8169 -> Bitmap Index Scan on t1_alternate_ids_idx (cost=0.00..44.48 rows=10567 width=0) (actual time=3.665..3.665 rows=10635 loops=1) Index Cond: (alternate_ids @> '{42}'::text[]) Planning time: 0.274 ms Execution time: 15.411 ms
如果您不熟悉 Postgres 執行計劃:大約 15 毫秒(毫秒)內從該表中檢索到這 10635 行
然而,一個適當規範化的模型也可以正常工作。它可能會給你更多的靈活性。具有數百萬行的表不是問題。甚至數億,取決於您訪問它們的方式。