需要帮助了解 NpgSQL 连接打开过程
Need help understanding NpgSQL connection opening process
我一直在尝试优化使用 NpgSQL 3.2.7 连接到 PostgreSQL 9.3 数据库的 Web 服务。今天我安装了 pgBouncer 并注意到 运行ning "select * from pg_stat_activity;" 我所有的 NpgSQL 连接都列出了这个查询:
SELECT ns.nspname, a.typname, a.oid, a.typrelid, a.typbasetype,
CASE WHEN pg_proc.proname='array_recv' THEN 'a' ELSE a.typtype END AS type,
CASE
WHEN pg_proc.proname='array_recv' THEN a.typelem
WHEN a.typtype='r' THEN rngsubtype
ELSE 0
END AS elemoid,
CASE
WHEN pg_proc.proname IN ('array_recv','oidvectorrecv') THEN 3 /* Arrays last */
WHEN a.typtype='r' THEN 2 /* Ranges before */
WHEN a.typtype='d' THEN 1 /* Domains before */
ELSE 0 /* Base types first */
END AS ord
FROM pg_type AS a
JOIN pg_namespace AS ns ON (ns.oid = a.typnamespace)
JOIN pg_proc ON pg_proc.oid = a.typreceive
LEFT OUTER JOIN pg_type AS b ON (b.oid = a.typelem)
LEFT OUTER JOIN pg_range ON (pg_range.rngtypid = a.oid)
WHERE
(
a.typtype IN ('b', 'r', 'e', 'd') AND
(b.typtype IS NULL OR b.typtype IN ('b', 'r', 'e', 'd')) /* Either non-array or array of supported element type */
)
当我在 pgAdmin 中 运行 这个查询需要 3 到 5 秒才能完成第二次我 运行 它应该缓存所有内容。当我有 运行 时,我的代码以交互方式执行 Web 服务调用中的第一个打开命令需要 3 到 5 秒。
每次创建连接时都会运行吗?在我看来,这是获取一些相对静态数据的昂贵查询。如果每次创建连接时都必须 运行,那么有人对如何在 Web 服务中围绕此进行架构有任何建议吗?每次调用 Web 服务 3 到 5 秒的开销太大了。使用池是否会影响此查询是否为 运行?
添加:2018 年 3 月 14 日
这些是我在创建 table 以保存类型查询的结果后看到的日志条目。它 运行 成功了,后来由于某种原因找不到 table。
2018-03-14 15:35:42 EDT 日志:持续时间:0.715 毫秒解析:select nspname、typname、oid、typrelid、typbasetype、type、elemoid、ord 来自 "public" ."npgsqltypes"
2018-03-14 15:35:42 EDT 日志:持续时间:0.289 毫秒绑定:select nspname、typname、oid、typrelid、typbasetype、type、elemoid、ord 来自 "public" ."npgsqltypes"
2018-03-14 15:35:42 EDT 日志:执行:select nspname,typname,oid,typrelid,typbasetype,type,elemoid,ord from "public"."npgsqltypes"
2018-03-14 15:35:42 EDT 日志:持续时间:0.391 毫秒
2018-03-14 15:35:44 EDT 错误:关系 "public.npgsqltypes" 在字符 71
处不存在
2018-03-14 15:35:44 EDT 声明:select nspname、typname、oid、typrelid、typbasetype、type、elemoid、ord 来自 "public"。"npgsqltypes"
2018-03-14 15:35:44 EDT 日志:声明:全部丢弃
2018-03-14 15:35:44 EDT 日志:持续时间:0.073 毫秒
添加:2018 年 3 月 15 日
解释类型查询的输出:
Sort (cost=3015139.78..3018795.67 rows=1462356 width=213)
Sort Key: (CASE WHEN (pg_proc.proname = ANY ('{array_recv,oidvectorrecv}'::name[])) THEN 3 WHEN (a.typtype = 'r'::"char") THEN 2 WHEN (a.typtype = 'd'::"char") THEN 1 ELSE 0 END)
-> Hash Left Join (cost=920418.37..2779709.53 rows=1462356 width=213)
Hash Cond: (a.oid = pg_range.rngtypid)
-> Hash Join (cost=920417.24..2752289.21 rows=1462356 width=209)
Hash Cond: ((a.typreceive)::oid = pg_proc.oid)
-> Hash Join (cost=919817.78..2724270.58 rows=1462356 width=149)
Hash Cond: (a.typnamespace = ns.oid)
-> Hash Left Join (cost=919305.50..2687199.40 rows=1462356 width=89)
Hash Cond: (a.typelem = b.oid)
Filter: (((a.typtype = ANY ('{b,r,e,d}'::"char"[])) AND ((b.typtype IS NULL) OR (b.typtype = ANY ('{b,r,e,d}'::"char"[])))) OR ((a.typname = ANY ('{record,void}'::name[])) AND (a.typtype = 'p'::"char")))
-> Seq Scan on pg_type a (cost=0.00..694015.89 rows=13731889 width=89)
-> Hash (cost=694015.89..694015.89 rows=13731889 width=5)
-> Seq Scan on pg_type b (cost=0.00..694015.89 rows=13731889 width=5)
-> Hash (cost=388.79..388.79 rows=9879 width=68)
-> Seq Scan on pg_namespace ns (cost=0.00..388.79 rows=9879 width=68)
-> Hash (cost=465.87..465.87 rows=10687 width=68)
-> Seq Scan on pg_proc (cost=0.00..465.87 rows=10687 width=68)
-> Hash (cost=1.06..1.06 rows=6 width=8)
-> Seq Scan on pg_range (cost=0.00..1.06 rows=6 width=8)
你是对的,这个查询是由 Npgsql 发出的,用于从 PostgreSQL 后端加载所有类型——不同的数据库可以有不同的数据类型(由于扩展、user-defined 类型等)。
但是,此查询仅在与特定数据库的第一个物理连接上发送,由其连接字符串标识。换句话说,如果你连接到同一个数据库 X 次——连接到同一个连接字符串——你应该只会看到这个查询被发送一次。 Npgsql 在内部缓存这些信息。我刚刚验证这是 3.2.7 中的行为,您是否看到其他情况?
我一直在尝试优化使用 NpgSQL 3.2.7 连接到 PostgreSQL 9.3 数据库的 Web 服务。今天我安装了 pgBouncer 并注意到 运行ning "select * from pg_stat_activity;" 我所有的 NpgSQL 连接都列出了这个查询:
SELECT ns.nspname, a.typname, a.oid, a.typrelid, a.typbasetype,
CASE WHEN pg_proc.proname='array_recv' THEN 'a' ELSE a.typtype END AS type,
CASE
WHEN pg_proc.proname='array_recv' THEN a.typelem
WHEN a.typtype='r' THEN rngsubtype
ELSE 0
END AS elemoid,
CASE
WHEN pg_proc.proname IN ('array_recv','oidvectorrecv') THEN 3 /* Arrays last */
WHEN a.typtype='r' THEN 2 /* Ranges before */
WHEN a.typtype='d' THEN 1 /* Domains before */
ELSE 0 /* Base types first */
END AS ord
FROM pg_type AS a
JOIN pg_namespace AS ns ON (ns.oid = a.typnamespace)
JOIN pg_proc ON pg_proc.oid = a.typreceive
LEFT OUTER JOIN pg_type AS b ON (b.oid = a.typelem)
LEFT OUTER JOIN pg_range ON (pg_range.rngtypid = a.oid)
WHERE
(
a.typtype IN ('b', 'r', 'e', 'd') AND
(b.typtype IS NULL OR b.typtype IN ('b', 'r', 'e', 'd')) /* Either non-array or array of supported element type */
)
当我在 pgAdmin 中 运行 这个查询需要 3 到 5 秒才能完成第二次我 运行 它应该缓存所有内容。当我有 运行 时,我的代码以交互方式执行 Web 服务调用中的第一个打开命令需要 3 到 5 秒。
每次创建连接时都会运行吗?在我看来,这是获取一些相对静态数据的昂贵查询。如果每次创建连接时都必须 运行,那么有人对如何在 Web 服务中围绕此进行架构有任何建议吗?每次调用 Web 服务 3 到 5 秒的开销太大了。使用池是否会影响此查询是否为 运行?
添加:2018 年 3 月 14 日 这些是我在创建 table 以保存类型查询的结果后看到的日志条目。它 运行 成功了,后来由于某种原因找不到 table。
2018-03-14 15:35:42 EDT 日志:持续时间:0.715 毫秒解析:select nspname、typname、oid、typrelid、typbasetype、type、elemoid、ord 来自 "public" ."npgsqltypes"
2018-03-14 15:35:42 EDT 日志:持续时间:0.289 毫秒绑定:select nspname、typname、oid、typrelid、typbasetype、type、elemoid、ord 来自 "public" ."npgsqltypes"
2018-03-14 15:35:42 EDT 日志:执行:select nspname,typname,oid,typrelid,typbasetype,type,elemoid,ord from "public"."npgsqltypes"
2018-03-14 15:35:42 EDT 日志:持续时间:0.391 毫秒
2018-03-14 15:35:44 EDT 错误:关系 "public.npgsqltypes" 在字符 71
处不存在2018-03-14 15:35:44 EDT 声明:select nspname、typname、oid、typrelid、typbasetype、type、elemoid、ord 来自 "public"。"npgsqltypes"
2018-03-14 15:35:44 EDT 日志:声明:全部丢弃
2018-03-14 15:35:44 EDT 日志:持续时间:0.073 毫秒
添加:2018 年 3 月 15 日
解释类型查询的输出:
Sort (cost=3015139.78..3018795.67 rows=1462356 width=213)
Sort Key: (CASE WHEN (pg_proc.proname = ANY ('{array_recv,oidvectorrecv}'::name[])) THEN 3 WHEN (a.typtype = 'r'::"char") THEN 2 WHEN (a.typtype = 'd'::"char") THEN 1 ELSE 0 END)
-> Hash Left Join (cost=920418.37..2779709.53 rows=1462356 width=213)
Hash Cond: (a.oid = pg_range.rngtypid)
-> Hash Join (cost=920417.24..2752289.21 rows=1462356 width=209)
Hash Cond: ((a.typreceive)::oid = pg_proc.oid)
-> Hash Join (cost=919817.78..2724270.58 rows=1462356 width=149)
Hash Cond: (a.typnamespace = ns.oid)
-> Hash Left Join (cost=919305.50..2687199.40 rows=1462356 width=89)
Hash Cond: (a.typelem = b.oid)
Filter: (((a.typtype = ANY ('{b,r,e,d}'::"char"[])) AND ((b.typtype IS NULL) OR (b.typtype = ANY ('{b,r,e,d}'::"char"[])))) OR ((a.typname = ANY ('{record,void}'::name[])) AND (a.typtype = 'p'::"char")))
-> Seq Scan on pg_type a (cost=0.00..694015.89 rows=13731889 width=89)
-> Hash (cost=694015.89..694015.89 rows=13731889 width=5)
-> Seq Scan on pg_type b (cost=0.00..694015.89 rows=13731889 width=5)
-> Hash (cost=388.79..388.79 rows=9879 width=68)
-> Seq Scan on pg_namespace ns (cost=0.00..388.79 rows=9879 width=68)
-> Hash (cost=465.87..465.87 rows=10687 width=68)
-> Seq Scan on pg_proc (cost=0.00..465.87 rows=10687 width=68)
-> Hash (cost=1.06..1.06 rows=6 width=8)
-> Seq Scan on pg_range (cost=0.00..1.06 rows=6 width=8)
你是对的,这个查询是由 Npgsql 发出的,用于从 PostgreSQL 后端加载所有类型——不同的数据库可以有不同的数据类型(由于扩展、user-defined 类型等)。
但是,此查询仅在与特定数据库的第一个物理连接上发送,由其连接字符串标识。换句话说,如果你连接到同一个数据库 X 次——连接到同一个连接字符串——你应该只会看到这个查询被发送一次。 Npgsql 在内部缓存这些信息。我刚刚验证这是 3.2.7 中的行为,您是否看到其他情况?