在AND组合的WHERE子句中的行筛选统计信息

时间:2014-09-13 10:08:32

标签: sql postgresql query-optimization

网站存储有关大量项目的所有规格的信息,并通过在前端添加一些过滤条件,为用户提供搜索数据的能力。在后端,所有条件都被转换为子句,并由AND操作数连接。

我的目的是让用户知道每个过滤器后丢弃或丢弃的商品数量。确切的数字对于初始筛分不是很重要(一些模糊或近似很好,因为整个数量非常大),但在后期阶段,当剩下十个左右的项目时,用户应该得到适当的数量。

有明显直接的方式来制作尽可能多的SELECT COUNT查询,因为他有过滤器,但我觉得可能是一种技术以更优雅的方式存档它并且不会滥用DB。

1 个答案:

答案 0 :(得分:1)

有很多方法可以通过不同程度的难度和性能实现这一目标。

对我来说,第一个也是最明显的方法是简单地对过滤器进行计数,这些过滤器表现相当不错并且难以实现。另一种类似的方法是按值进行分组并进行计数。

这里有一个小提琴作为两种方法的例子:http://sqlfiddle.com/#!15/0cdcb/26

select
    count(product.id) total,
    sum((v0.value = 'spam')::int) v0_is_spam,
    sum((v0.value != 'spam')::int) v0_not_spam,
    sum((v1.value = 'spam')::int) v1_is_spam,
    sum((v1.value != 'spam')::int) v1_not_spam
from product
left join specification_value v0 on v0.product_id = product.id and v0.specification_id = 1
left join specification_value v1 on v1.product_id = product.id and v1.specification_id = 2;

select specification.id, value, count(*)
from specification
left join specification_value on specification.id = specification_value.specification_id
group by specification.id, value;

执行类似操作的一种稍微困难的方法是使用窗口函数,更灵活但不易掌握。文档在这里:http://www.postgresql.org/docs/9.3/static/tutorial-window.html

示例查询和结果:

SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary;
  depname  | empno | salary |          avg          
-----------+-------+--------+-----------------------
 develop   |    11 |   5200 | 5020.0000000000000000
 develop   |     7 |   4200 | 5020.0000000000000000
 develop   |     9 |   4500 | 5020.0000000000000000
 develop   |     8 |   6000 | 5020.0000000000000000
 develop   |    10 |   5200 | 5020.0000000000000000
 personnel |     5 |   3500 | 3700.0000000000000000
 personnel |     2 |   3900 | 3700.0000000000000000
 sales     |     3 |   4800 | 4866.6666666666666667
 sales     |     1 |   5000 | 4866.6666666666666667
 sales     |     4 |   4800 | 4866.6666666666666667
(10 rows)

最后,到目前为止最快但也最不准确且难以实施。使用数据库统计信息来猜测行数。我不会选择这个,除非你在过滤器集中有数百万行,并且无法进一步减少它。此外,除非表现非常糟糕,否则不要这样做。