我有一个containers
可以与多个表建立多对多关系的表,假设它们是plants
,animals
和bacteria
。每个容器可以包含任意数量的植物、动物或细菌,并且每个植物、动物或细菌可以在任意数量的容器中。
到目前为止,这非常简单,但我遇到的问题是每个容器应该只包含相同类型的元素。例如,同时包含植物和动物的混合容器应该是数据库中的约束违规。
我的原始架构如下:
containers
----------
id
...
...
containers_plants
-----------------
container_id
plant_id
containers_animals
------------------
container_id
animal_id
containers_bacteria
-------------------
container_id
bacterium_id
Run Code Online (Sandbox Code Playgroud)
但是对于这个模式,我无法想出如何实现容器应该是同构的约束。
有没有办法通过参照完整性来实现这一点,并在数据库级别确保容器是同类的?
我为此使用 Postgres 9.6。
我注意到涉及 jsonb 列的查询的性能在测试时在 VACUUM ANALYZE 运行之间存在显着差异。分析表格后,我似乎随机得到了完全不同的执行计划。
我在这里使用 Postgres 9.6。我的测试设置如下,我将一个键“x”插入到 jsonb 列“params”中,值在 1 到 6 之间,1 是最稀有的值,6 是最常见的值。我还有一个常规的 int 列“single_param”,其中包含用于比较的相同值分布。:
CREATE TABLE test_data (
id serial,
single_param int,
params jsonb
);
INSERT INTO test_data
SELECT
generate_series(1, 1000000) AS id,
floor(log(random() * 9999999 + 1)) AS single_param,
json_build_object(
'x', floor(log(random() * 9999999 + 1))
) AS params;
CREATE INDEX idx_test_btree ON test_data (cast(test_data.params->>'x' AS int));
CREATE INDEX idx_test_gin ON test_data USING GIN (params);
CREATE INDEX ON test_data(id)
CREATE INDEX ON test_data(single_param)
Run Code Online (Sandbox Code Playgroud)
我正在测试的查询是对结果进行分页的典型查询,我按 …
我正在使用node-postgres连接到启用了连接池的 PostgreSQL 9.6 数据库。所有连接都使用同一个数据库用户。我不能使用多个数据库用户的一个原因是,据我所知,在这种情况下,行级安全性和视图不能很好地协同工作,因为视图的所有者用于 RLS。
我现在正在考虑在 Postgres 中使用行级安全性,我想确保我这样做是正确的。
我正在使用SET LOCAL
设置当前应用程序用户 ID,然后由行级安全性 USING 子句使用。我能想到通过连接池实现这一点的唯一方法是使用 node-postgres 将每个查询包装在一个事务中,并SET LOCAL
在每个事务中执行如下命令。
SET LOCAL postgres.my_user = 20;
Run Code Online (Sandbox Code Playgroud)
以下代码是我想如何定义行级安全性的简化示例,真实版本还有一些条件:
CREATE POLICY table_a_read_policy ON table_a FOR SELECT
USING (
EXISTS (
SELECT *
FROM permissions
WHERE
user_id = current_setting('postgres.my_user')::int AND
permission_type = 'read'
)
);
Run Code Online (Sandbox Code Playgroud)
我的理解是,在这种情况下,任何 SQL 注入也会使攻击者能够以这种方式设置任何用户 ID 并规避行级安全性。但是我没有看到任何方法可以避免这种情况,因为我连接的数据库用户必须能够查看整个应用程序的所有数据。
有几点我不完全确定:
SET LOCAL
作为存储当前应用程序用户身份以实现行级安全的方式是否安全?尤其是在连接池的上下文中?SET LOCAL
每次执行命令更好的方法?我有一个查询,我想从 date_ added 列排序的表数据集中获取前几行。排序依据的列被索引,所以这个表的基本版本非常快:
SELECT datasets.id FROM datasets ORDER BY date_added LIMIT 25
Run Code Online (Sandbox Code Playgroud)
"Limit (cost=0.28..6.48 rows=25 width=12) (actual time=0.040..0.092 rows=25 loops=1)"
" -> Index Scan using datasets_date_added_idx2 on datasets (cost=0.28..1244.19 rows=5016 width=12) (actual time=0.037..0.086 rows=25 loops=1)"
"Planning time: 0.484 ms"
"Execution time: 0.139 ms"
Run Code Online (Sandbox Code Playgroud)
但是一旦我使查询变得更复杂,我就会遇到问题。我想加入另一个表示多对多关系的表,并将结果聚合在一个数组列中。为此,我需要添加一个 GROUP BY id 子句:
SELECT datasets.id FROM datasets GROUP BY datasets.id ORDER BY date_added LIMIT 25
Run Code Online (Sandbox Code Playgroud)
"Limit (cost=551.41..551.47 rows=25 width=12) (actual time=9.926..9.931 rows=25 loops=1)"
" -> Sort (cost=551.41..563.95 rows=5016 width=12) (actual time=9.924..9.926 rows=25 loops=1)"
" …
Run Code Online (Sandbox Code Playgroud) postgresql performance optimization postgresql-9.5 query-performance
postgresql ×4
constraint ×1
index-tuning ×1
json ×1
many-to-many ×1
optimization ×1
performance ×1
statistics ×1