ruby-on-rails - 更快地搜索字段的第一个字符与 [A-Za-z] 不匹配的记录?

标签 ruby-on-rails ruby-on-rails-3 postgresql postgresql-performance

我目前有以下内容:

User (id, fname, lname, deleted_at, guest)

我可以通过用户的 fname 首字母查询用户列表,如下所示:

User Load (9.6ms)  SELECT "users".* FROM "users" WHERE (users.deleted_at IS NULL) AND (lower(left(fname, 1)) = 's') ORDER BY fname ASC LIMIT 25 OFFSET 0

这要归功于以下索引:

  CREATE INDEX users_multi_idx
  ON users (lower(left(fname, 1)), fname)
  WHERE deleted_at IS NULL;

我现在想要做的是能够查询所有不以字母 A-Z 开头的用户。我让它像这样工作:

SELECT "users".* FROM "users" WHERE (users.deleted_at IS NULL) AND (lower(left(fname, 1)) ~ E'^[^a-zA-Z].*') ORDER BY fname ASC LIMIT 25 OFFSET 0

但问题是这个查询很慢而且似乎没有使用索引来加速第一个查询。关于如何优雅地使第二个查询(非 a-z)更快的任何建议?

我正在使用带有 Rails 3.2 的 Postgres 9.1

谢谢

最佳答案

更新的答案
Preceding question here.

我的第一个想法(索引为 text_pattern_ops )在我的测试中不适用于正则表达式。最好将您的查询重写为:

SELECT *
FROM   users
WHERE  deleted_at IS NULL
<b>WHERE lower(left(fname, 1)) < 'a' COLLATE "C"
OR    lower(left(fname, 1)) > 'z' COLLATE "C"</b>
ORDER  BY fname
LIMIT  25 OFFSET 0;

除了这些表达式通常更快之外,您的正则表达式中还包含大写字母,这与 lower() 的索引不匹配。与单个字符相比,尾随字符毫无意义。

并使用这个索引:

CREATE INDEX users_multi_idx
ON users (lower(left(fname, 1)) <b>COLLATE "C"</b>, fname)
WHERE deleted_at IS NULL;

COLLATE "C"部分是可选的,只会带来非常小的性能提升。它的目的是将排序规则重置为默认的 posix 排序规则,它只使用字节顺序并且通常更快。在归类规则无论如何都不相关的情况下很有用。

如果您使用它创建索引,则只有与排序规则匹配的查询才能使用它。因此,如果性能不是您的首要要求,您可以跳过它以简化事情。

关于ruby-on-rails - 更快地搜索字段的第一个字符与 [A-Za-z] 不匹配的记录?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12906264/

相关文章:

ruby-on-rails - Rails - 用户在创建对象后按下 'Back',创建重复项

sql - 选择另一列必须匹配两个特定选项之一的位置

ruby-on-rails - 在远程应用程序上运行 rake 任务,使用本地机器上的文件

ruby-on-rails - 在使用主干 rails 的实心仪表时从 highcharts 得到错误#17

ruby-on-rails - 如何在 Ruby 中构建 JSON 代码

html - Rails 如何在 HABTM 模型 Controller 中写入 "Create" Action

sql - Postgresql GROUP BY 取决于另一列的值

postgresql - 如何在不达到 max_stack_depth 的情况下更新与 plpgsql 中的插入/更新相同的行

javascript - 为什么我在执行 Controller 索引操作时无法通过 Rails 执行 AJAX?

ruby-on-rails - 从数据库中删除旧记录 (Postgres/Rails)