Postgresql
SELECT COUNT(*) 返回不正確的結果
我在 RDS Aurora 上的 PostgreSQL 9.6.3 上看到了一些非常奇怪的行為。
我從某些查詢中得到重複的結果:
=> select count(id) from foos where id = 'deadbeef'; count ------- 2 (1 row) => select id from foos where id = 'deadbeef'; id -------------------------- deadbeef deadbeef (2 rows) => select id, created_at from foos where id = 'deadbeef'; id | created_at --------------------------+---------------------------- deadbeef | 2018-01-01 10:00:00.000000 (1 row)
(id 值、時間戳和表名已被混淆)
我在這個表上沒有表繼承,也沒有任何其他表。
這似乎只影響恰好命中
foos
表上一個索引的查詢。因為這似乎與單個索引隔離,我想執行
REINDEX
可能會解決這個問題。但是,我不知道有多少索引表現出這種行為。
例如,以下是通過不同索引對同一記錄的類似行為:
=> select bar from foos where bar = 'qux'; bar ----------------------------------------- qux qux (2 rows) => select id from foos where bar = 'qux'; id -------------------------- deadbeef (1 row) => select bar, id from foos where bar = 'qux'; bar | id -----------------------------------------+-------------------------- qux | deadbeef (1 row) => select bar, created_at from foos where bar = 'qux'; bar | created_at -----------------------------------------+---------------------------- qux | 2018-01-01 10:00:00.000000 (1 row)
以下是該表的相關索引:
Indexes: "pk_foos" PRIMARY KEY, btree (id) "index_foos_on_bar" UNIQUE, btree (bar)
這是前幾個範例的解釋計劃:
=> explain select id from foos where id = 'deadbeef'; QUERY PLAN ---------------------------------------------------------------------------- Index Only Scan using pk_foos on foos (cost=0.42..8.44 rows=1 width=25) Index Cond: (id = 'deadbeef'::text) (2 rows) => explain select id, created_at from foos where id = 'deadbeef'; QUERY PLAN ----------------------------------------------------------------------- Index Scan using pk_foos on foos (cost=0.42..8.44 rows=1 width=33) Index Cond: (id = 'deadbeef'::text) (2 rows)
這裡發生了什麼?
或者,我怎樣才能弄清楚這裡發生了什麼?
這當然看起來像一個損壞的索引。首先,拍攝數據庫快照並將其儲存在沒有人可以寫入的地方。
這是 RDS Aurora 而不是社區 PostgreSQL,您的第一個(也可能是最後一個)資源將是與 AWS 支持人員交談。
如果需要,您可以嘗試重新索引整個數據庫,但如果索引損壞,表中也可能損壞。當然,如果您執行的任何數據修改未能更新他們應該擁有的所有行,或者如果您根據業務決策修改了任何數據,這些決策依賴於錯誤結果的查詢,那麼這種類型的損壞將是不可見的。重新索引(或任何繼續使用數據庫)可能會破壞可能對腐敗的取證分析有用的證據,因此上面的“第一件事”。
如果您設置數據保留,以便您可以將時間點恢復到遙遠的過去,您可以進行測試以查看任何特定損壞實例出現的時間點。