Bey*_*tun 5 postgresql relational-division
一个 Item 有许多 ItemDetails。ItemDetail 具有“type”、“value”和“item_id”字段。
当且仅当项目具有受某些可变条件限制的确切ItemDetails 时,我才需要找到所有项目。例如,我需要查找 ItemDetails 为 (type=10, value=1000) 和 (type=20 and value=2000) 的所有项目
我的第一个解决方案是这样的:
select p.*
from item p
where not exists
(
select c.id from item_detail c
where c.item_id=p.id
and (c.type<>10 or c.value<>1000)
and (c.type<>20 or c.value<>2000)
);
-- Execution Time: 17.819 ms
Run Code Online (Sandbox Code Playgroud)
但我意识到它只获取一个 ItemDetail(type=10, value=1000) 的项目。然后我发现了这个问题并改变了如下查询。
select p.*
from item p
where not exists
(
select c.id from item_detail c
where c.item_id=p.id
and (c.type<>10 or c.value<>1000)
and (c.type<>20 or c.value<>2000)
)
and 2 = (
select count(c.item_id) from item_detail c
where c.item_id=p.id);
-- Execution Time: 2426.596 ms
Run Code Online (Sandbox Code Playgroud)
但是第二个子查询导致了性能问题。第一个查询的执行时间为 5 毫秒,但第二个查询的执行时间为 800 毫秒。有没有更好的方法来做到这一点?
我正在使用 PostgreSQL 9.5。
这是它的小提琴。
编辑1:这是那些无法到达的人的小提琴示例:
CREATE TABLE public.item
(
id integer NOT NULL,
name character varying(10) NOT NULL,
CONSTRAINT item_pkey PRIMARY KEY (id)
);
CREATE TABLE public.item_detail
(
id bigint NOT NULL,
item_id integer NOT NULL,
type integer NOT NULL,
value integer NOT NULL,
CONSTRAINT item_detail_pkey PRIMARY KEY (id),
CONSTRAINT fk_item_id FOREIGN KEY (item_id)
REFERENCES item (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT uq_item_type_value UNIQUE (item_id, type, value)
);
INSERT INTO public.item VALUES (1, 'Item1'),(2, 'Item2'),(3, 'Item3'),(4, 'Item4'),(5, 'Item5');
INSERT INTO public.item_detail
VALUES
(1,1,10,1000),
(2,1,20,2000),
(3,2,10,1000),
(4,3,10,1000),
(5,3,20,2000),
(6,3,30,3000),
(7,4,10,1000),
(8,4,10,1500);
Run Code Online (Sandbox Code Playgroud)
编辑2:我想出了类似的解决方案这样的选择对我来说,从最好的选择这个源通过ypercube ??给出。
SELECT p.* FROM item p
WHERE EXISTS (SELECT item_id FROM item_detail
WHERE item_id = p.id AND (type, value) = (10, 1000))
AND EXISTS (SELECT item_id FROM item_detail
WHERE item_id = p.id AND (type, value) = (20, 2000))
AND NOT EXISTS (SELECT item_id FROM item_detail
WHERE item_id = p.id AND (type, value) NOT IN ((10, 1000), (20,2000)));
-- Execution Time: 0.984 ms
Run Code Online (Sandbox Code Playgroud)
我们试图解决的问题称为精确关系划分。它需要关系划分的额外条件,并且仍然有很多(实际上太多)方法来解决此类问题。
检查这个相关的SO问题,你会发现在Postgres和性能测试中有超过10种不同的方法来做到这一点。那里讨论的问题是(简单的,不精确的)关系划分,所以你必须调整答案:
这是另一个:
select p.*
from item p
join
( select item_id from item_detail
where (type, value) = (10, 1000)
intersect
select item_id from item_detail
where (type, value) = (20, 2000)
except
select item_id from item_detail
where (type, value) not in ((10, 1000), (20, 2000))
) as c
on c.item_id = p.id ;
Run Code Online (Sandbox Code Playgroud)
我建议在 上建立索引(type, value, item_id)
。
归档时间: |
|
查看次数: |
7910 次 |
最近记录: |