我需要一些优化从大表中获取查询的技巧。
在这个例子中我有5个表:
Brands
- id_brand
- b_name
Products
- id_product
- p_name
- ean
...
- fk_brand
Prod_attributes
- id_prod_att
- size_basic
...
- fk_product
Stores
- id_store
- s_name
...
Stocks
- id_stock
- stock_amount
- fk_prod_att
- fk_store
我需要查询有序的股票有序列表,所以这是我使用的一般方法:
SELECT stores.s_name, stocks.stock_amount, prod_attributes.size_basic,
products.p_name, products.ean, brands.b_name
FROM (stocks
INNER JOIN stores
ON stocks.fk_store = stores.id_store)
INNER JOIN (prod_attributes
INNER JOIN (products
INNER JOIN brands
ON products.fk_brand = brands.id_brand)
ON prod_attributes.fk_product = products.id_product)
ON stocks.fk_prod_att = prod_attributes.id_prod_att
ORDER BY s_name, p_name, size_basic
LIMIT 25 OFFSET 0
这适用于小型表,但是当表增长时,查询变得非常昂贵。 Stocks中有3,5M行,Prod_attributes中有300K,超过8800ms时执行25K产品,这对我来说是不可接受的。
所有forgein键都有索引,DB最近已经过真空分析。
我知道问题出在ORDER BY部分,因为查询不使用索引并进行顺序扫描。如果我删除了排序,那么查询速度非常快。
为了解决这个问题,我知道我可以删除ORDER BY,但对我来说这不是一个可行的选择。数据库或物化视图的反规范化也可以在这里提供帮助 - 如果可能的话,我想再次避免这种情况。
我还能做些什么来加快查询速度?
EXPLAIN ANALYZE:
- 订单减慢:http://explain.depesz.com/s/AHO
- 快速无订单:http://explain.depesz.com/s/NRxr
答案 0 :(得分:1)
可行的方法是从联接中删除stores
。相反,你可以:
在存储过程或源代码中循环stores
(按s_name
排序),对于每个商店,在stocks.fk_store
上执行联接过滤。只要获得足够数量的记录,就可以打破循环。
如果可能,请使用stocks
键对fk_store
进行分区,以便大量减少连接中元组的数量。
通过这种方式你应该有一个很好的好处。