我有一个调查数据数据库,如下所示:

create table Products(
    Id int primary key,
    Name nvarchar(max)
)

create table Opinions(
    Id int primary key,
    ProductId int foreign key references Products(Id),
    IsEasyToUse bit default((0)),
    IsGoodPrice bit default((0)),
    IsDurable bit default((0)),
-- and so on...
)

我想创建一个报表,显示Opinions表中的每个产品和所有意见列的百分比.

到目前为止,我一直在用天真的方式做这件事:

select 
    p.Name,
    1.0 *
        (select count(*) from Opinions o where o.ProductId = p.Id and o.IsEasyToUse = 1) / 
        (select count(*) from Opinions o where o.ProductId = p.Id) as EasyToUse,
    1.0 *
        (select count(*) from Opinions o where o.ProductId = p.Id and o.IsGoodPrice = 1) /
        (select count(*) from Opinions o where o.ProductId = p.Id) as GoodPrice,
    1.0 *
        (select count(*) from Opinions o where o.ProductId = p.Id and o.IsDurable = 1) /
        (select count(*) from Opinions o where o.ProductId = p.Id) as Durable
from
(select Id, Name from Products) p

这在技术上是可行的,但我对重复出现的条件并不满意.另外,Options表的大小越来越大,因此性能问题开始变得明显(现在1M行需要大约一分钟的时间).

有没有一种方法可以用一种更快的方式重写它(将来如果我想要应用更多的过滤器,也更容易修改)?

推荐答案

首先:我们可以连接和聚合,而不是执行多个相关子查询.

那么:我们不需要计算总计数;相反,我们只需要JUSE avg();对聚合函数的较少调用应该会提高查询效率:

select p.id, p.name
    avg(case when IsEasyToUse = 1 then 1.0 else 0 end) as EasyToUse,
    avg(case when IsGoodPrice = 1 then 1.0 else 0 end) as GoodPrice,
    avg(case when IsDurable   = 1 then 1.0 else 0 end) as Durable 
from products p
inner join opinions o on o.productID = p.id
group by p.id, p.name

根据您的数据在两个表中的分布情况,apply可能是一个很好的替代方案,因为它避免了外部聚合:

select p.id, p.name, x.*
from products p
cross apply (
    select 
        avg(case when IsEasyToUse = 1 then 1.0 else 0 end) as EasyToUse,
        avg(case when IsGoodPrice = 1 then 1.0 else 0 end) as GoodPrice,
        avg(case when IsDurable   = 1 then 1.0 else 0 end) as Durable 
    from opinions o 
    where o.productID = p.id
) x

Sql相关问答推荐

获取每个帖子的匹配关键字列表

PostgreSQL:如果发现多行具有相似列值,则跳过 Select 行

为什么postgres中CURRENT_TIMESTAMP的日期与CURRENT_DATE不同?

从列的不同值创建列

前面的语句不喜欢AND LIKE?当try 更新使用ID和日期过滤的表时

为什么在postgres中,横向连接比相关子查询快?

每组显示一行(表1中的分组值),表2中的不同列表用逗号分隔

使用列表作为参数进行 Select ,如果为空,则在PostgreSQL中不使用参数进行 Select

从包含PostgreSQL中的JSON值的列中提取列表或目录

在PostgreSQL中汇总连接表中的 case 值

按两列分组,并根据SQL中的条件返回第三个列值

通过对象分离实现原子性

从单个表达式中的分隔字符串中取平均值

使用递归CTE在BigQuery中获取文件路径

在同一列上迭代时计算持续时间

Grafana SQL 模板变量(值、文本)

Postgresql 生成器列导致语法错误

如何对 jsonb 中的字段执行求和,然后使用结果过滤查询的输出

多列上的 SQL UNIQUE 约束 - 它们的组合必须是唯一的还是至少其中之一?

如何刷新在视图之上创建的表