【问题标题】:Behavior of WHERE clause on a primary key field主键字段上 WHERE 子句的行为
【发布时间】:2017-06-30 05:31:07
【问题描述】:
select * from table where username="johndoe"

在 Postgres 中,如果用户名不是主键,我知道它会遍历所有记录。

但是如果是主键字段,上面的SQL语句会遍历整个表,还是只要匹配到username就终止。换句话说,“where”在主键列上运行时的行为是否不同?

【问题讨论】:

  • 为什么会有一个名为johndoe的列?有关数据库如何使用索引的详细信息,您可能需要阅读use-the-index-luke.com
  • 'johndoe' 不是一列。 “用户名”是一列。 'johndoe' 是列中的一个条目
  • "johndoe" 是一个标识符(=column),'johndoe' 是一个字符串值
  • 非常感谢。我从来不知道双引号和单引号在 SQL 中的含义不同
  • @KeyurPanchal:不,不会。如果有索引,数据库将使用该索引来查找行。

标签: sql postgresql


【解决方案1】:

当这些列用作过滤谓词时,主键(以及所有索引列)利用索引,例如WHEREJOIN...ON 子句。

作为一个真实的例子,我的应用程序有一个名为 Log_Games 的表,这是一个有数百万行的表,ID 作为主键,还有许多其他非索引列,例如 ParsedAt .比较以下:

索引查询

EXPLAIN ANALYZE
SELECT *
FROM "Log_Games"
WHERE "ID" = 792046

索引查询计划

Index Scan using "Log_Games_pkey" on "Log_Games"  (cost=0.43..8.45 rows=1 width=4190) (actual time=0.024..0.024 rows=1 loops=1)
  Index Cond: ("ID" = 792046)
Planning time: 1.059 ms
Execution time: 0.066 ms

非索引查询

EXPLAIN ANALYZE
SELECT *
FROM "Log_Games"
WHERE "ParsedAt" = '2015-05-07 07:31:24+00'

非索引查询计划

Seq Scan on "Log_Games"  (cost=0.00..141377.34 rows=18 width=4190) (actual time=0.013..793.094 rows=1 loops=1)
  Filter: ("ParsedAt" = '2015-05-07 07:31:24+00'::timestamp with time zone)
  Rows Removed by Filter: 1924676
Planning time: 0.794 ms
Execution time: 793.135 ms

带有索引子句的查询使用索引Log_Games_pkey,导致查询在 0.066 毫秒内执行。带有非索引子句的查询将恢复为顺序扫描,这意味着它会从表的开始到结束查看哪些列匹配,这一操作会导致执行时间超过 793.135 毫秒。

网络上有很多很好的资源可以帮助您阅读执行计划并决定何时需要支持索引。一个好的起点是 PostgreSQL 文档: https://www.postgresql.org/docs/9.6/static/using-explain.html

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多