- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有两个表:
CREATE TABLE items
(
root_id integer NOT NULL,
id serial NOT NULL,
-- Other fields...
CONSTRAINT items_pkey PRIMARY KEY (root_id, id)
)
CREATE TABLE votes
(
root_id integer NOT NULL,
item_id integer NOT NULL,
user_id integer NOT NULL,
type smallint NOT NULL,
direction smallint,
CONSTRAINT votes_pkey PRIMARY KEY (root_id, item_id, user_id, type),
CONSTRAINT votes_root_id_fkey FOREIGN KEY (root_id, item_id)
REFERENCES items (root_id, id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE,
-- Other constraints...
)
我试图在单个查询中提取特定 root_id 的所有项目以及以特定方式投票的用户的一些 user_id 数组。以下查询满足我的需要:
SELECT *,
ARRAY(SELECT user_id from votes where root_id = i.root_id AND item_id = i.id AND type = 0 AND direction = 1) as upvoters,
ARRAY(SELECT user_id from votes where root_id = i.root_id AND item_id = i.id AND type = 0 AND direction = -1) as downvoters,
ARRAY(SELECT user_id from votes where root_id = i.root_id AND item_id = i.id AND type = 1) as favoriters
FROM items i
WHERE root_id = 1
ORDER BY id
问题是我正在使用三个子查询来获取我需要的信息,而我似乎应该能够在一个子查询中执行相同的操作。我认为 Postgres(我使用的是 8.4)可能足够聪明,可以为我将它们全部折叠成一个查询,但是查看 pgAdmin 中的解释输出,看起来这并没有发生——它正在对选票运行多个主键查找表代替。我觉得我可以重新处理此查询以提高效率,但我不确定该怎么做。
有什么建议吗?
编辑:更新以解释我现在的位置。根据 pgsql-general 邮件列表的建议,我尝试更改查询以使用 CTE:
WITH v AS (
SELECT item_id, type, direction, array_agg(user_id) as user_ids
FROM votes
WHERE root_id = 5305
GROUP BY type, direction, item_id
ORDER BY type, direction, item_id
)
SELECT *,
(SELECT user_ids from v where item_id = i.id AND type = 0 AND direction = 1) as upvoters,
(SELECT user_ids from v where item_id = i.id AND type = 0 AND direction = -1) as downvoters,
(SELECT user_ids from v where item_id = i.id AND type = 1) as favoriters
FROM items i
WHERE root_id = 5305
ORDER BY id
从我的应用程序中对每一个进行基准测试(我将每个设置为准备好的语句以避免在查询计划上花费时间,然后使用各种 root_id 运行每个语句数千次)我的初始方法平均为 15 毫秒,CTE接近平均 17 毫秒。我能够在几次运行中重复这个结果。
当我有时间的时候,我会用我的测试数据来尝试 jkebinger 和 Dragontamer5788 的方法,看看它们是如何工作的,但我也会开始悬赏,看看我是否能得到更多建议。
我还应该提到,如果它可以加快此查询,我愿意更改我的模式(系统尚未投入生产,并且不会在几个月内投入生产)。我以这种方式设计了我的投票表,以利用主键的唯一性约束——例如,给定的用户既可以喜欢也可以投票赞成一个项目,但不能赞成它也可以反对它——但我可以放松/解决这个约束,如果代表这些选项以不同的方式更有意义。
编辑 #2: 我已经对所有四种解决方案进行了基准测试。令人惊讶的是,Sequel足够灵活,我可以编写所有四个语句而无需掉落到 SQL 一次(甚至对于 CASE 语句也不异常(exception))。像以前一样,我将它们全部作为准备好的语句运行,这样查询计划时间就不会成为问题,并且每个运行了数千次。然后我在两种情况下运行所有查询——最坏的情况是有很多行(265 项和 4911 票),相关行很快就会在缓存中,所以 CPU 使用率应该是决定因素,而且更多为每次运行选择随机 root_id 的现实场景。我结束了:
Original query - Typical: ~10.5 ms, Worst case: ~26 ms
CTE query - Typical: ~16.5 ms, Worst case: ~70 ms
Dragontamer5788 - Typical: ~15 ms, Worst case: ~36 ms
jkebinger - Typical: ~42 ms, Worst case: ~180 ms
我想现在从中吸取的教训是 Postgres 的查询规划器非常聪明,并且可能在表面下做一些聪明的事情。我认为我不会再花时间尝试解决它。如果有人想提交另一个查询尝试,我很乐意对其进行基准测试,但除此之外,我认为 Dragontamer 是赏金和正确(或最接近正确)答案的赢家。除非其他人能够阐明 Postgres 正在做什么——那会很酷。 :)
最佳答案
有两个问题:
对于 #1,我无法将“完整”的东西放入单个 Common Table Expression 中,因为您在每个项目上使用相关子查询。不过,如果您使用公用表表达式,您可能会有一些好处。显然,这将取决于数据,因此请进行基准测试以查看是否有帮助。
对于 #2,因为您的表中有三个经常访问的项目“类”,我预计 partial indexes提高查询速度,无论您是否能够由于 #1 提高速度。
首先,简单的事情。要向该表添加部分索引,我会这样做:
CREATE INDEX upvote_vote_index ON votes (type, direction)
WHERE (type = 0 AND direction = 1);
CREATE INDEX downvote_vote_index ON votes (type, direction)
WHERE (type = 0 AND direction = -1);
CREATE INDEX favoriters_vote_index ON votes (type)
WHERE (type = 1);
这些索引越小,查询的效率就越高。不幸的是,在我的测试中,它们似乎没有帮助:-( 不过,也许您可以找到它们的用途,这在很大程度上取决于您的数据。
至于整体优化,我会以不同的方式处理问题。我将查询“展开”为这种形式(使用内部联接并使用 conditional expressions 来“拆分”三种类型的选票),然后使用“Group By”和“数组”聚合运算符将它们组合起来. IMO,我宁愿更改我的应用程序代码以接受它的“展开”形式,但如果您不能更改应用程序代码,那么“分组依据”+聚合函数应该可以工作。
SELECT array_agg(v.user_id), -- array_agg(anything else you needed),
i.root_id, i.id, -- I presume you needed the primary key?
CASE
WHEN v.type = 0 AND v.direction = 1
THEN 'upvoter'
WHEN v.type = 0 AND v.direction = -1
THEN 'downvoter'
WHEN v.type = 1
THEN 'favoriter'
END as vote_type
FROM items i
JOIN votes v ON i.root_id = v.root_id AND i.id = v.item_id
WHERE i.root_id = 1
AND ((type=0 AND (direction=1 OR direction=-1))
OR type=1)
GROUP BY i.root_id, i.id, vote_type
ORDER BY id
与您的代码相比,它仍然是“展开的一步”(vote_type 是垂直的,而在您的情况下,它是水平的,跨列)。但这似乎更有效率。
关于sql - 在 Postgres 中将多个子查询合并为一个,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7165272/
这个问题在这里已经有了答案: How to initialize var? (11 个答案) 关闭 8 年前。 我想给一个变量赋初值 null,并在下一个 if-else block 中赋值,但是编
我正在使用 TypeScript 3.8 编写 JS 和 TS 混合的代码。我写了以下行: export * as Easing from './easing'; 应该是 fair game在 Typ
我需要将 R 代码中的“/”更改为“\”。我有这样的事情: tmp <- paste(getwd(),"tmp.xls",sep="/") 所以我的 tmp是 c:/Study/tmp.xls 我希望
我有个问题。例如我有这个: id truth count 1 1 1 2 1 2 3 0 0 4 1 1 5 1 2 6 1
我正在尝试使用“IN”和“=”来查找一些 bean。我目前正在使用此代码: $ids = array(1,2,3,4); $user = 1; $things = R::find( 'thing'
是否可以在 Xcode 中部署到其他人的手机上?我没有 iPhone,但我想测试我在 friend 手机上制作的应用程序。在我支付 99 美元之前,我想确保这不会造成麻烦。 谢谢。 最佳答案 不会有任
我试图得到一个非常大的数字(超过 unsigned long long int )。所以我把它作为一个字符串,然后一个数字一个数字地转换成整数并使用它。 #include #include int
我在 Rust 中有 C 语言库的绑定(bind),但它们并不完整。 在 C 代码中,我定义了一个简化的宏,如下所示: #define MY_MACROS1(PTR) (((my_struct1
我正在努力解决这个问题。 http://jsfiddle.net/yhcqfy44/ 动画应该自动相对于 滚动到顶部每次出现滚动条时的高度。 我已经写了这个,但没有运气: var hheight =
我正在处理一个将数字作为字符串返回的 JSON API。例如 "12" ,但是,该字段值也可以是非数字的,例如:"-" . 我已将 JSON 数据解析为映射,我想将此字段提取为 elixir 中的整数
我正在尝试编写一个类,将.wav文件转换为.aiff文件作为项目的一部分。 我遇到了几个库Alvas.Audio(http://alvas.net/alvas.audio,overview.aspx)
我想在 Lucene 中将像“New York”这样的“复合词”索引为单个术语,而不是像“new”、“york”那样。这样,如果有人搜索“new place”,则包含“new york”的文档将不会匹
我希望这个解释能让我更好地了解使用宏的优点。 最佳答案 在函数中,所有参数在调用之前都会被评估。 这意味着 or 作为函数不能是惰性的,而宏可以将 or 重写为 if 语句,该语句仅在以下情况下计算分
我有一些看起来像这样的 XML foo ]]> (注意 > 登录 "> foo")和 XSLT 样式表 当我运行xsltproc stylesheet.xs
当我尝试将 Any 转换为 List 时,如下面的示例所示,我得到“Unchecked cast: Any!”到列表'警告。有没有解决此类问题的方法? val x: List = objectOfTy
我正在使用 Python 开发一个简单的爬虫。目的是创建一个 sitemap.xml。(你可以在这里找到真正的 alpha 版本:http://code.google.com/p/sitemappy/
我想知道在 VBScript 中是否可以在多行中中断 If 语句。喜欢: If (UCase(Trim(objSheet.Cells(i, a).Value)) = "YES") Or _ (UCas
for (String item : someList) { System.out.println(item); } 使用“do while”是否等效? 谢谢。 最佳答案 如果列表为空,f
这个问题已经有答案了: 已关闭10 年前。 Possible Duplicate: Split string with delimiters in C 在 C 中将“,”分隔的列表拆分为数组的最佳方法
我有一个如下所示的字符数组: [0, 10, 20, 30, 670] 如何将此字符串转换为整数数组? 这是我的数组 int i=0; size_t dim = 1; char* array = (c
我是一名优秀的程序员,十分优秀!