繁体   English   中英

如何有效地搜索匹配Rails和PostgreSQL中的条件的最后一条记录?

[英]How to efficiently search for last record matching a condition in Rails and PostgreSQL?

假设您要查找输入到与字符串匹配的数据库中的最后一条记录(最高ID)Model.where(:name => 'Joe') 有超过100,000条记录。 有很多比赛(比如数千)。

最有效的方法是什么? PostgreSQL需要找到所有记录,还是只能找到最后一个? 这是一个特别慢的查询吗?

使用Rails 3.0.7,Ruby 1.9.2和PostgreSQL 8.3。

这里的重要部分是具有匹配的索引 您可以尝试这个小测试设置:

创建用于测试的模式x

-- DROP SCHEMA x CASCADE;  -- to wipe it all for a retest or when done.
CREATE SCHEMA x;
CREATE TABLE x.tbl(id serial, name text);

插入10000个随机行:

INSERT INTO x.tbl(name) SELECT 'x' || generate_series(1,10000);

插入另外10000行重复的名称:

INSERT INTO x.tbl(name) SELECT 'y' || generate_series(1,10000)%20;

随机删除10%,使其更真实:

DELETE FROM x.tbl WHERE random() < 0.1;

ANALYZE x.tbl;

查询可能如下所示:

SELECT *
FROM   x.tbl
WHERE  name = 'y17'
ORDER  BY id DESC
LIMIT  1;

- >总运行时间:5.535毫秒

CREATE INDEX tbl_name_idx on x.tbl(name);

- >总运行时间:1.228 ms

DROP INDEX x.tbl_name_idx;
CREATE INDEX tbl_name_id_idx on x.tbl(name, id);

- >总运行时间:0.053毫秒

DROP INDEX x.tbl_name_id_idx;
CREATE INDEX tbl_name_id_idx on x.tbl(name, id DESC);

- >总运行时间:0.048 ms

DROP INDEX x.tbl_name_id_idx;
CREATE INDEX tbl_name_idx on x.tbl(name);
CLUSTER x.tbl using tbl_name_idx;

- >总运行时间:1.144 ms

DROP INDEX x.tbl_name_id_idx;
CREATE INDEX tbl_name_id_idx on x.tbl(name, id DESC);
CLUSTER x.tbl using tbl_name_id_idx;

- >总运行时间:0.047毫秒

结论

使用拟合索引,查询执行速度提高了100多倍
最佳执行者是多列索引,首先是过滤列,最后是排序列。
在这种情况下,索引中的匹配排序顺序有点帮助。

聚类有助于简单索引,因为仍然需要从表中读取许多列,并且这些列可以在聚类后在相邻块中找到。 在这种情况下,它对多列索引没有帮助,因为只需从表中获取一个记录。
阅读手册中有关多列索引的更多信息。

所有这些效果都随着桌子的大小而增长。 10000行的两个小列只是一个非常小的测试用例。

您可以将查询放在Rails中,ORM将编写正确的SQL:

Model.where(:name=>"Joe").order('created_at DESC').first

这不应导致检索所有模型记录,甚至也不会检索表扫描。

这可能是最简单的:

SELECT [columns] FROM [table] WHERE [criteria] ORDER BY [id column] DESC LIMIT 1

注意:索引在这里很重要。 如果您没有以正确的方式编制索引,那么无论您如何操作,巨大的数据库都会很慢。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM