大量列或行的最佳數據庫
問題1:
我有一個包含 567 行和 16,382 列的文件,其中大部分是浮點數。我有另一個包含 117,493 行但只有 3 列的文件。內容涉及生物學和遺傳學。
我不知道文件中的數字是什麼意思。這是一個大學項目,我必須能夠在不知道內容是什麼的情況下查詢給定文件的不同內容。我假設我們不應該規範化數據,因為這需要理解內容。我們根據性能和選擇哪些數據庫的理由進行評分。
文件 1:(567 行,16,382 列)
我一直讓人們對這個文件中的列數感到驚訝。這些列大多是帶有一堆數字的遺傳資訊,無法標準化。我最初認為 Postgresql 對File 1有好處,但我讀到它們是一個面向行的數據庫,所以這太可怕了。我讀到 Cassandra 非常適合面向列的查找,但問題是大多數列和行都包含數據並且大部分是結構化的,除了一些沒有值的區域。使用 Cassandra 還是一個更好的主意嗎?
文件 1的操作:
- 簡單的查找
- 求均值
- 找到標準差
我無法確認 SQL 和 NoSQL 在聚合函式(例如計算平均值和標準差)上的一般性能。所以這是選擇我的數據庫的另一個因素。我會假設 Cassandra 比 Postgresql 更快,因為 Cassandra 是面向列的。
文件 2:(117,493 行,3 列)
每一行和每一列都包含數據。我猜 Postgresql 在這裡很好,因為只有 3 列但 117,493 行,Postgresql 是面向行的,並且沒有失去數據。在這種情況下是否有更好的 NoSQL 替代方案?鍵值儲存 NoSQL 會更好嗎,因為它主要用於檢索?
文件 2的操作:
- 簡單的查找
問題2:
我擁有的大多數大文件都通過某種 ID 相關聯,例如File 1和File 2。如果我對File 2使用 Postgresql ,對File 1使用Cassandra ,會不會有相當大的性能損失?通常您會將相關表儲存在 RDMS 中,但文件 1的列數是否意味著使用混合方法更好?
PostgreSQL
@Dobob 一切都可以標準化 :) 如果不是很秘密,它是什麼類型的數據?(作為一名遺傳學家出身的 DBA 提問。)
這通常是正確的。你應該開始研究如何標準化。顯然你反對這個想法,你不能總是正常化。例如,柵格通常是來自科學儀器的讀數的集合,您無法真正對其進行非規範化。它們是同時採集的,代表相同的樣本,並且經常有 1,000 個數據點。(儘管現在您可以將它們儲存在 PostGIS 中)。
問題 1 的解決方案
PostgreSQL 不支持表上的 16,383 列(或超過 1,600+ 列),但它支持SQL Arrays。你可能可以利用它,
CREATE TABLE foo AS SELECT r AS id, array_agg(c) AS genetic_stuff FROM generate_series(1,567) AS r CROSS JOIN LATERAL generate_series(1,16382) AS c GROUP BY r;
現在您有一個符合第一個條件但並不瘋狂的表。
Table "public.foo" Column | Type | Modifiers ---------------+-----------+----------- id | integer | genetic_stuff | integer[] |
求平均值很簡單..
SELECT id, avg(x) FROM foo CROSS JOIN LATERAL unnest(genetic_stuff) AS t(x) GROUP BY id;
而對於整個操作
Execution time: 3865.308 ms
!可以投訴那個。MATERIALIZED VIEW
如果您想記憶體該平均值,請隨意使用。對於標準偏差,只需使用適當的聚合函式代替
avg()
. 執行時間大致相同。我不確定你是如何在這裡查詢這個的,但是沒有索引(最壞的情況)非常簡單和快速(考慮到它是一個 seq 掃描)掃描一個包含 16,000 個項目的數組對於現代的 a CPU,在 PostgreSQL 9.6 上,這個 seq 掃描甚至應該並行執行(afaik)。
SELECT * FROM foo WHERE genetic_stuff @> ARRAY[5];
可以使用索引嗎?當然。從
intarray
模組,提供了兩個 GiST 索引運算符類:gist__int_ops(預設使用)適用於中小型數據集,而 gist__intbig_ops 使用較大的簽名,更適用於索引大型數據集(即包含大量不同的數組值)。該實現使用具有內置有損壓縮的 RD-tree 資料結構。
讓我們試一試…
CREATE INDEX ON foo USING gist(genetic_stuff gist__intbig_ops); VACUUM FULL foo; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------- Index Scan using foo_genetic_stuff_idx on foo (cost=0.14..8.16 rows=1 width=22) (actual time=0.119..47.846 rows=567 loops=1) Index Cond: (genetic_stuff @> '{5}'::integer[]) Planning time: 0.072 ms Execution time: 47.948 ms (4 rows)
不知道你想要什麼而不是索引掃描。如果不是每一行都有一個元素,可能會更有用
5
,但您知道它只是範例數據。反正有它。
問題 2 的解決方案
害羞的是,另一件事根本不是問題,因為 Pg 行很胖,但你不是在說很多行,最終它應該不重要,下面的表格滿足標準只有 5088 kB我的系統。幾乎不值得關心自己。
CREATE TABLE baz AS SELECT x AS id, x*2 AS x2, x*3 AS x3, x*4 AS x4 FROM generate_series(1,117493) AS t(x);