Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 将Postgres索引添加到一个表会锁定另一个表_Sql_Postgresql_Amazon Web Services - Fatal编程技术网

Sql 将Postgres索引添加到一个表会锁定另一个表

Sql 将Postgres索引添加到一个表会锁定另一个表,sql,postgresql,amazon-web-services,Sql,Postgresql,Amazon Web Services,我关注单个Postgres 9.3.3(Amazon RDS实例:db.m3.2xlarge),它是系统的后端,记录传入的统计数据并基于这些数据提供报告-是的,来自同一个db节点 性能通常非常好,但在表R上添加额外索引以提高报告性能后,日志性能崩溃,因为日志过程使用的不同表L上的INSERTs和UPDATEs立即开始锁定-根据pg_locks,似乎彼此锁定,尽管没有报告死锁。立即,所有可用的连接(根据pg_stat_activity)以相同的方式锁定,DB CPU迅速上升到100%。记录器的负载

我关注单个Postgres 9.3.3(Amazon RDS实例:db.m3.2xlarge),它是系统的后端,记录传入的统计数据并基于这些数据提供报告-是的,来自同一个db节点

性能通常非常好,但在表R上添加额外索引以提高报告性能后,日志性能崩溃,因为日志过程使用的不同表L上的
INSERT
s和
UPDATE
s立即开始锁定-根据
pg_locks
,似乎彼此锁定,尽管没有报告死锁。立即,所有可用的连接(根据pg_stat_activity)以相同的方式锁定,DB CPU迅速上升到100%。记录器的负载平衡器使其所有节点停止使用,但由于
插入
s和
更新
s拒绝完成或超时,所有连接保持锁定

请注意,这在索引创建期间不是问题,只是在使用期间。这也不是一个负载问题:将日志记录限制90%,然后重新完全启动系统,立即将其锁定。同时没有任何报道

立即删除R索引将释放所有L锁

我使用以下方法创建索引:

CREATE INDEX idxForGroup ON R (group,article_id,month);
其中列为:

'group' type: VARCHAR(64) defaultValue: "" nullable: false
'month' type: TIMESTAMP nullable: false
'article_id' type: BIGINT defaultValue: 0 nullable: false
已经有一个复合主键,上面只是其中的一个子集:

customer_resource_id (a FK), subtype (a VARCHAR), group, article_id, month
我应该补充一点,R和L之间存在关系:触发器根据L的更新更新报告表R:

CREATE TRIGGER on_event_report AFTER INSERT OR UPDATE ON L FOR EACH ROW EXECUTE PROCEDURE resource_event_trigger();
我承认添加任何索引都会带来很小的(微秒?)成本/负载,但是R上已经有索引了,所以我不明白为什么R上的“一点”额外索引会产生如此巨大的影响,从而导致L的锁定


更新:

如果我调查被锁定的L查询:

EXPLAIN (analyze,buffers) update L set count=count+1 where customer_resource_id=911657 and item_type_id='type' and event_subtype='subtype' and reporting_date='2014-04-13 00:00:00' AND group='';
 Update on L  (cost=0.57..20.18 rows=5 width=49) (actual time=70.968..70.968 rows=0 loops=1)
   Buffers: shared hit=170 read=16 dirtied=15
   ->  Index Scan using L_pkey on L  (cost=0.57..20.18 rows=5 width=49) (actual time=0.067..0.525 rows=19 loops=1)
         Index Cond: ((customer_resource_id = 911657) AND ((group)::text = ''::text) AND ((item_type_id)::text = 'type'::text) AND ((event_subtype)::text = 'subtype'::text) AND (article_id = 0))
         Buffers: shared hit=24
 Trigger on_L: time=11626.219 calls=19 <---
 Total runtime: 11697.285 ms
删除索引,然后在几秒钟内:

      mode       | count 
-----------------+-------
 ExclusiveLock   |     3
 AccessShareLock |    31

更新3:

以下是日志记录表L上更新报告表R的触发器的来源:

CREATE OR REPLACE FUNCTION resource_event_trigger()
RETURNS TRIGGER AS $$
DECLARE
cre_row R%ROWTYPE;
delta INTEGER;
BEGIN
SELECT * INTO cre_row FROM R cre WHERE cre.customer_resource_id = NEW.customer_resource_id AND cre.group = NEW.group_id AND cre.subtype = NEW.event_subtype AND cre.date = date_trunc('month', NEW.date) AND cre.article_id = NEW.article_id;

IF cre_row IS null THEN
INSERT INTO R (customer_resource_id, group, subtype, article_id, date) VALUES (NEW.customer_resource_id, NEW.group_id, NEW.event_subtype, NEW.article_id, date_trunc('month', NEW.date));
END IF;

IF TG_OP = 'INSERT' THEN
delta = NEW.event_count;
ELSE
delta = NEW.event_count - OLD.event_count;
END IF;

CASE
WHEN NEW.item_type_id = 'typeA' THEN
UPDATE R SET count_A = count_A + delta WHERE customer_resource_id = NEW.customer_resource_id AND group = NEW.group_id AND subtype = NEW.event_subtype AND article_id = NEW.article_id AND date = date_trunc('month', NEW.date);
[...]
END CASE;

RETURN NEW;
END;
$$
LANGUAGE plpgsql;
它很长,但很简单。单独“解释”时,所有单独的查询都使用主键/索引,使用很少的缓冲区等


更新4:

如果检查创建的索引,我会注意到:

选择tablename、attname、n_distinct、与pg_stats的相关性,其中tablename='R'和attname按attname排序('group'、'article\u id'、'date'、'customer\u resource\u id'、'subtype')

 tablename |       attname        | n_distinct | correlation 
-----------+----------------------+------------+-------------
 R         | article_id           |      25886 |    0.756468
 R         | group                |        165 |    0.227023
 R         | customer_resource_id |  -0.304469 |    0.729134
 R         | date                 |         53 |    0.943593
 R         | subtype              |          2 |    0.657429
。。。这看起来很有道理。如果我看一下基数,我会得到:

SELECT relname, relkind, reltuples as cardinality, relpages FROM pg_class where relkind='i' [...] order by relname;

   relname   | relkind | cardinality | relpages 
-------------+---------+-------------+----------
 R_pkey      | i       | 2.69955e+07 |   293035
 idxForGroup | i       | 2.70333e+07 |   134149
 L_pkey      | i       | 7.14889e+07 |   771581

PK和新添加的索引的值几乎与行计数相同,这同样应该是好的…

虽然我不能确切地说您的问题可能是什么,但它显然取决于这个新索引。如果我能彻底地看清楚事情,肯定会容易些,但我会在黑暗中拍几张照片

索引和博士后的表现可能是一个大问题,但从根本上说,我认为有一些事情可能是错误的,你应该检查一下:

当更改/添加表上的索引时,查询优化器(在查询开始前的毫秒激发,并评估如何最好地执行该查询)当然会以不同的方式查看表。它看到:“嘿,这里有一个新的索引,也许这比我使用的旧索引要好”,在某些情况下,查询优化器可能是错误的

因此,优化器不再使用工作正常的过去索引,而是开始执行完整表扫描或其他愚蠢的操作。这是一种极端情况,但当然可能发生

另一件事是,你可能正在处理很多“死囚”。每当您要更新表时,它都会创建一个“死行”,并插入一个新的(更新的行)。“死行”实际上并不会出现在任何地方,有时会使您的表膨胀,Postgres查询优化器可能会在试图理解这一点时有些混乱

有一次,我有一张桌子像这样疯了,我一辈子都不明白它为什么走得这么慢。然后,我看了看表格统计数据,发现数十万行死了。我在黑暗中拍摄了一张照片,只是删除并重新创建了表(尽管这需要在实时数据库上做一些工作),然后神奇地一切都正常工作(表结构或表中的数据没有任何更改,只是删除表实例时完全释放了死行)

虽然这有点极端,但我要立即做的是:

a) 在桌子上运行真空吸尘器,这是一个很好的慢跑,可以让“死行”远离障碍


b) 然后在表上运行分析。这将重新设置表汇总统计信息,优化器将在其中获取大量数据以确定查询表的最佳方式。

有趣!当您以90%的容量减少启动系统并立即锁定时,是否有任何锁定被清除?从表面上看,触发因素可能是在新指数上做了一些需要更多时间的事情。我不能100%地说他们不清楚,但他们没有在合理的时间内这样做。通常需要约1毫秒的L更新将需要1小时以上的时间。这可能是一种极端的性能下降,锁只是仍在运行的查询的一种症状。对于grins来说,如果没有新的索引,解释会是什么样子?如果我读的是正确的解释,那是一个11秒的触发器调用。这不太好。没有索引,计划是一样的,只是触发器需要0.377ms,而不是11626.219ms。明白了,你有没有尝试过在postgresql.conf中碰撞共享缓冲区、临时缓冲区、工作缓冲区?也许新的索引将mem命中推回到磁盘提取。我不熟悉aws的mem/磁盘性能。也许在上面的桌子上做个真空分析?
SELECT relname, relkind, reltuples as cardinality, relpages FROM pg_class where relkind='i' [...] order by relname;

   relname   | relkind | cardinality | relpages 
-------------+---------+-------------+----------
 R_pkey      | i       | 2.69955e+07 |   293035
 idxForGroup | i       | 2.70333e+07 |   134149
 L_pkey      | i       | 7.14889e+07 |   771581