Ruby on rails RAILS SQL子查询优化
我有一个查询,如下所示:Ruby on rails RAILS SQL子查询优化,ruby-on-rails,postgresql,crosstab,find-by-sql,aggregate-filter,Ruby On Rails,Postgresql,Crosstab,Find By Sql,Aggregate Filter,我有一个查询,如下所示: @inventory = Pack.find_by_sql("SELECT Packs.id, "+ " (SELECT COUNT(*) FROM Stocks WHERE (Stocks.pack_id = Packs.id AND Stocks.status = 'online' AND Stocks.user_id = #{current_user.id})) AS online,"+ " (SELECT COUNT(*) FROM Stocks W
@inventory = Pack.find_by_sql("SELECT Packs.id, "+
" (SELECT COUNT(*) FROM Stocks WHERE (Stocks.pack_id = Packs.id AND Stocks.status = 'online' AND Stocks.user_id = #{current_user.id})) AS online,"+
" (SELECT COUNT(*) FROM Stocks WHERE (Stocks.pack_id = Packs.id AND Stocks.status = 'offline' AND Stocks.user_id = #{current_user.id})) AS offline,"+
" (SELECT COUNT(*) FROM Stocks WHERE (Stocks.pack_id = Packs.id AND Stocks.status = 'depositing' AND Stocks.user_id = #{current_user.id})) AS depositing,"+
" (SELECT COUNT(*) FROM Stocks WHERE (Stocks.pack_id = Packs.id AND Stocks.status = 'withdrawing' AND Stocks.user_id = #{current_user.id})) AS withdrawing,"+
" (SELECT COUNT(*) FROM Stocks WHERE (Stocks.pack_id = Packs.id AND Stocks.status = 'selling' AND Stocks.user_id = #{current_user.id})) AS selling,"+
" (SELECT COUNT(*) FROM Transactions WHERE (Transactions.pack_id = Packs.id AND Transactions.status = 'buying' AND Transactions.buyer_id = #{current_user.id})) AS buying"+
" FROM Packs WHERE disabled = false")
@inventory = Pack.find_by_sql("SELECT status, count(*)
FROM stocks
WHERE user_id = ?
GROUP BY status
ORDER BY status", current_user.id)
我在想有一种方法可以创建一个新的子查询,这样就可以代替
SELECT FROM Stocks
查询从存储的表中进行选择
SELECT FROM (Stocks WHERE (Stocks.pack_id = Packs.id AND Stocks.user_id = #{current_user.id}))
只能查询一次。然后将WHERE Stocks.status=?
内容应用于该存储表
有什么帮助吗?如果您想要的是各种类型的计数,那么像下面这样的代码会少得多,而且更易于阅读/维护,我想 您可以将它们拆分为不同的表,因此,对于
股票
,如下所示:
@inventory = Pack.find_by_sql("SELECT Packs.id, "+
" (SELECT COUNT(*) FROM Stocks WHERE (Stocks.pack_id = Packs.id AND Stocks.status = 'online' AND Stocks.user_id = #{current_user.id})) AS online,"+
" (SELECT COUNT(*) FROM Stocks WHERE (Stocks.pack_id = Packs.id AND Stocks.status = 'offline' AND Stocks.user_id = #{current_user.id})) AS offline,"+
" (SELECT COUNT(*) FROM Stocks WHERE (Stocks.pack_id = Packs.id AND Stocks.status = 'depositing' AND Stocks.user_id = #{current_user.id})) AS depositing,"+
" (SELECT COUNT(*) FROM Stocks WHERE (Stocks.pack_id = Packs.id AND Stocks.status = 'withdrawing' AND Stocks.user_id = #{current_user.id})) AS withdrawing,"+
" (SELECT COUNT(*) FROM Stocks WHERE (Stocks.pack_id = Packs.id AND Stocks.status = 'selling' AND Stocks.user_id = #{current_user.id})) AS selling,"+
" (SELECT COUNT(*) FROM Transactions WHERE (Transactions.pack_id = Packs.id AND Transactions.status = 'buying' AND Transactions.buyer_id = #{current_user.id})) AS buying"+
" FROM Packs WHERE disabled = false")
@inventory = Pack.find_by_sql("SELECT status, count(*)
FROM stocks
WHERE user_id = ?
GROUP BY status
ORDER BY status", current_user.id)
请注意使用?
防止SQL注入的重要性。此外,Ruby支持多行字符串,因此不需要引用和连接每一行
您可以对其他表执行类似操作。最佳查询取决于数据分布和其他详细信息 只要子查询中的大多数
pack\u id
实际用于连接到packs
(大多数pack
未禁用),这是非常有效的:
在pg9.4中,您可以使用聚合筛选子句:
SELECT pack_id
, count(*) FILTER (WHERE status = 'online') AS online
, count(*) FILTER (WHERE status = 'offline') AS offline
, count(*) FILTER (WHERE status = 'depositing') AS depositing
, count(*) FILTER (WHERE status = 'withdrawing') AS withdrawing
, count(*) FILTER (WHERE status = 'selling') AS selling
FROM stocks
WHERE ...
详情:
交叉表()
可以加快速度,但:
SELECT p.id
, s.online, s.offline, s.depositing, s.withdrawing, s.selling, t.buying
FROM packs p
LEFT JOIN crosstab(
$$
SELECT pack_id, status, count(*)::int AS ct
FROM stocks
WHERE user_id = $$ || #{current_user.id} || $$
AND status = ANY('{online,offline,depositing,withdrawing,selling}'::text[])
GROUP BY 1, 2
ORDER BY 1, 2
$$
,$$SELECT unnest('{online,offline,depositing,withdrawing,selling}'::text[])$$
) s (pack_id int
, online int
, offline int
, depositing int
, withdrawing int
, selling int
) USING (pack_id)
LEFT JOIN (
SELECT pack_id, count(*) AS buying
FROM transactions
WHERE status = 'buying'
AND buyer_id = #{current_user.id}
) t ON t.pack_id = p.id
WHERE NOT p.disabled;
为什么是横向的?pg9.1中是否有替代方案
pack
是禁用的股票中有多少不同的价值。状态
?Freuquecies?等等。我添加了更多的选项。天哪,你对sql有着疯狂的了解。我需要读一些书来了解这里发生了什么,lol。谢谢你的帮助。我会在再次测试后回复你的安装一个更大的对象池。我想我应该升级到第9.4页。9.5已经发布了还是仅仅是他们的文档?@AronGreenspan:9.5是新的devel版本。请等待升级,直到它发布。