Postgres查询花了很长时间才能得到结果

时间:2018-01-04 15:51:02

标签: ruby-on-rails postgresql rails-postgresql

我的postgres查询有问题。查询花了太长时间,差不多27秒才得到结果,我不知道我需要做什么来解决

SELECT 
    sales.*, 
    customers.name AS customer_name, 
    customers.cpf_pf AS cpf, 
    customers.cnpj_pj AS cnpj, 
    customers.juridica AS tipo_pessoa, 
    status_sales.name AS status_name, 
    sales_status_histories.created_at AS data_modificacao, 
    sales_status_histories.obs as observacao, 
    users.name AS nome_vendedor

FROM sales 

RIGHT JOIN customers ON sales.customer_id = customers.id
RIGHT JOIN sales_user_owners ON sales_user_owners.sale_id = sales.id
RIGHT JOIN sales_status_histories ON sales_status_histories.sale_id = sales.id
RIGHT JOIN status_sales ON status_sales.id = sales_status_histories.status_sale_id
RIGHT JOIN users ON users.id = sales_user_owners.user_id 

WHERE sales_status_histories.id IN (SELECT id FROM ( SELECT *, row_number() over (PARTITION BY sale_id ORDER BY created_at DESC) AS rn FROM sales_status_histories) AS ssh WHERE rn=1 AND Date( (sales_status_histories.created_at at time zone 'UTC') at time zone 'America/Sao_Paulo') BETWEEN '2018-01-01 00:00:00' AND '2018-01-04 23:59:59')
    AND sales_user_owners.id IN ( SELECT id FROM ( SELECT *, row_number() over (PARTITION BY sale_id ORDER BY created_at DESC) AS rn FROM sales_user_owners) AS so WHERE rn=1)

最大的问题在于:

WHERE sales_status_histories.id IN (SELECT id FROM ( SELECT *, row_number() over (PARTITION BY sale_id ORDER BY created_at DESC) AS rn FROM sales_status_histories) AS ssh WHERE rn=1 AND Date( (sales_status_histories.created_at at time zone 'UTC') at time zone 'America/Sao_Paulo') BETWEEN '2018-01-01 00:00:00' AND '2018-01-04 23:59:59')

此部分使用特定时间范围在sales_status_histories表中搜索销售的最后状态

销售可以在不同阶段具有倍数状态,但只有最后一个是当前状态,而最后一个对我来说在此查询中很重要,因为我需要获得在特定时间范围内更新的所有销售

有人可以帮我构建一个优化的查询,花费更少的时间来获得相同的结果吗?

在此图片中查看我的数据库的整个结构:image

我的应用程序是带有postgres的轨道上的红宝石

指标: enter image description here

---编辑1 ----

有时我需要找到具有特定当前状态的销售。使用@bma建议我试过这样的事情:

(SELECT id, row_number() OVER (PARTITION BY sale_id ORDER BY created_at DESC) AS rn FROM sales_status_histories WHERE status_sale_id IN (2) AND DATE((sales_status_histories.created_at AT TIME ZONE 'UTC') AT TIME ZONE 'America/Sao_Paulo') BETWEEN '2018-01-01' AND '2018-01-04') AS ssh WHERE rn=1

正如您所看到的,我添加了status_sale_id IN(2),但在这种情况下,只返回某个时刻(并非总是当前状态)具有该特定状态的销售

1 个答案:

答案 0 :(得分:0)

不是一个完整的答案,但是尝试的一件事可能是使用WITH子句使查询更具可读性,以便首先提取您感兴趣的sales_status_histories行,然后加入主SELECT。

注意:您可以使用SELECT DISTINCT sale_id FROM sales_status_histories ORDER BY created_at DESC仅获取具有最新更改的行而不是带有row_number()的子查询。我不知道这是否更有效,但阅读起来更简单。