假设您要查找与字符串匹配的最后一条输入数据库的记录(最高 ID)Model.where(:name => 'Joe')
: 。有 100,000 多条记录。有很多匹配项(比如数千个)。
最有效的方法是什么?PostgreSQL 需要查找所有记录,还是只查找最后一条?这是一个特别慢的查询吗?
在 Rails 3.0.7、Ruby 1.9.2 和 PostgreSQL 8.3 中工作。
假设您要查找与字符串匹配的最后一条输入数据库的记录(最高 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 毫秒
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 毫秒
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 毫秒
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
注意:索引在这里很重要。如果您没有以正确的方式建立索引,那么无论您如何进行搜索,一个巨大的数据库都会很慢。