2014-09-13 41 views
0

該網站存儲有關大量項目的所有規格的信息,並提供用戶通過在前端添加一些過濾條件來搜索數據的能力。在後端,所有條件都被翻譯成子句並由AND操作數加入。WHERE子句中的行篩選統計AND AND

我的目的是讓用戶知道在每個過濾器後有多少物品被丟棄或遺留。確切的數字對於初始篩選不是很重要(有些模糊或近似值是好的,因爲總量很大),但是在後面的階段,當剩下十個左右的項目時,用戶應該得到適當的數量。

有很明顯的簡單方法可以製作儘可能多的SELECT COUNT查詢,因爲他有過濾器,但我覺得這可能是一些技術,以更優雅的方式將其存檔,並且不會濫用數據庫。

回答

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) 

最後,迄今爲止最快也最不準確,難以實施。使用數據庫統計信息猜測行數。除非在過濾器集合中有數百萬行,並且無法進一步減少它,否則我不會選擇此選項。另外,除非性能非常糟糕以至於需要,否則不要這樣做。

+0

我覺得窗口函數可能是解決方案,但我的擔心主要是關於性能和多餘的查詢。比如說,我們拿到了手機規格的DB。在用戶設置cpu:arm,ram> 2Gb,防水和NFC之後,他應該得到這樣的數字 - 在第一次(cpu)過濾1000個手機之後,在ram-250之後,在防水之後 - 10以及在NFC之後 - 數據庫2之後。所以,如果我沒有弄錯,所有的方法(除了最後一個)都需要4個非常相似的查詢。最初,我甚至想通過解析「EXPLAIN」來從Query Planner獲取信息。 – 2014-09-13 15:51:55

+0

請注意,它可能會使一切都比簡單的查詢困難:)只要看看更新的版本,你可以在一個單一的查詢(除了實際的結果是)除外。 – Wolph 2014-09-13 16:23:20