【发布时间】:2014-06-21 23:14:39
【问题描述】:
我有一个名为evidence 的表,它带有一个触发器,该触发器调用一个存储过程,该存储过程基本上按月进行表分区。但是,当我开始在负载下插入大量行时,我得到一个模糊的错误:
Npgsql.NpgsqlException: query string argument of EXECUTE is null
Severity: ERROR Code: 22004 at Npgsql.NpgsqlState.<ProcessBackendResponses_Ver_3>d__a.MoveNext() in c:\C#Apps\github.npgsql.Npgsql.stock\src\Npgsql\NpgsqlState.cs:line890 at Npgsql.ForwardsOnlyDataReader.GetNextResponseObject() in c:\C#Apps\github.npgsql.Npgsql.stock\src\Npgsql\NpgsqlDataReader.cs:line 1175 at
Npgsql.ForwardsOnlyDataReader.GetNextRowDescription() in c:\C#Apps\github.npgsql.Npgsql.stock\src\Npgsql\NpgsqlDataReader.cs:line 1191 at
Npgsql.ForwardsOnlyDataReader.NextResult() in c:\C#Apps\github.npgsql.Npgsql.stock\src\Npgsql\NpgsqlDataReader.cs:line 1377 at
Npgsql.NpgsqlCommand.ExecuteNonQuery() in c:\C#Apps\github.npgsql.Npgsql.stock\src\Npgsql\NpgsqlCommand.cs:line523
我的系统具有自动重试功能,最终每条记录都会插入数据库,但在负载高时会出现许多异常。
数据库是 CentOS 6 服务器上的 PostgreSQL 9.3,客户端是使用 Npgsql 驱动程序的 C# .NET。
表格:
CREATE TABLE evidence
(
id uuid NOT NULL,
notification_id uuid NOT NULL,
feedback character varying(200),
result character varying(20),
trigger_action_type character varying(200),
trigger_action_id uuid,
data_type integer NOT NULL,
data bytea,
name character varying(30),
CONSTRAINT pk_evidence PRIMARY KEY (id)
);
触发器:
CREATE TRIGGER evidence_move_to_partition_tables
BEFORE INSERT
ON evidence
FOR EACH ROW
EXECUTE PROCEDURE partition_evidence_by_month();
触发功能:
CREATE OR REPLACE FUNCTION partition_evidence_by_month()
RETURNS trigger AS
$BODY$
DECLARE
_notification_id uuid;
_raised_local_time timestamp without time zone;
_table_name character varying(35);
_start_date timestamp without time zone;
_end_date timestamp without time zone;
_table_space character varying(50) := 'ls_tablespace2';
_query text;
BEGIN
_notification_id := NEW.notification_id;
SELECT raised_local_time FROM notifications WHERE id=_notification_id INTO _raised_local_time;
_start_date := date_trunc('month', _raised_local_time);
_end_date := _start_date + '1 month'::interval;
_table_name := 'evidence-' || to_char(_start_date, 'YYYY-MM');
-- check to see if table already exists
PERFORM 1
FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind = 'r'
AND c.relname = _table_name
AND n.nspname = 'public';
-- if the table doesn't exist, then create it now
IF NOT FOUND THEN
-- create partition table
_query := 'CREATE TABLE public.' || quote_ident(_table_name) || ' ( ) INHERITS (public.evidence)';
EXECUTE _query;
-- alter owner
--EXECUTE 'ALTER TABLE public.' || quote_ident(_table_name) || ' OWNER TO postgres';
-- add index
--EXECUTE 'ALTER TABLE public.' || quote_ident(_table_name) || ' ADD PRIMARY KEY (id)';
END IF;
-- move the data to the partition table
EXECUTE 'INSERT INTO public.' || quote_ident(_table_name) || ' VALUES ($1.*)' USING NEW;
RETURN NULL;
END;
$BODY$ LANGUAGE plpgsql VOLATILE COST 100;
调用代码:
using (var cmd = db.CreateCommand())
{
cmd.CommandText = @"INSERT INTO evidence
(id, notification_id, feedback, result, trigger_action_type,
trigger_action_id, data_type, data, name)
VALUES (@id,@nid,@feedback,@result,@tat,@taid,@dt,@data,@name)";
cmd.Parameters.AddWithValue("@id", evItem.ID);
cmd.Parameters.AddWithValue("@nid", evItem.NotificationID);
cmd.Parameters.AddWithValue("@feedback", evItem.Feedback);
cmd.Parameters.AddWithValue("@result", evItem.Result);
cmd.Parameters.AddWithValue("@tat", evItem.TriggerActionType);
cmd.Parameters.AddWithValue("@taid", evItem.TriggerActionID);
cmd.Parameters.AddWithValue("@dt", (int)evItem.DataType);
cmd.Parameters.AddWithValue("@data", evItem.Data);
cmd.Parameters.AddWithValue("@name", evItem.Name);
cmd.ExecuteNonQuery();
}
为什么这个奇怪的错误只有在系统负载时才会出现?我能做些什么来防止它发生?
谢谢!
【问题讨论】:
-
我什至设置了一个断点并对其进行了调试,并观察了 _query 变量在
EXECUTE _query失败之前被设置为一个有效的查询,但是如果我之后手动运行_query的值,它可以工作吗?! -
有趣。并发/线程问题,可能在 nPgSQL 中,可能在应用程序中?
-
这就是我的想法,虽然错误也出现在 PostgreSQL 的日志文件中,我在插入代码周围加了一个锁,它仍然抛出同样的错误:(
-
你试过用
RAISE LOG调试它吗? 可能更容易将它们与 PostgreSQL 日志中的错误相匹配。另外:您是否将evidence.notification_id上的外键设置为notifications.id? -
没有外键,这是完全反规范化的。不需要 RAISE LOG,因为我已经使用调试器逐步完成了它 - 查询没有任何问题,它可以在之后运行。有趣的是,我也可以通过使用 pgAdmin 手动输入数据来重现这一点!
标签: c# postgresql plpgsql npgsql postgresql-9.3