{"kind": "plan", "major": "18", "item": {"slug": "merge-join", "name": "Merge Join", "name_zh": "MergeJoin", "category": "\u8fde\u63a5", "summary": "\u4f7f\u7528\u5f52\u5e76\u6761\u4ef6\u8fde\u63a5\u6709\u5e8f\u8f93\u5165\u6d41\u3002", "aliases": ["Merge", "MergeJoin", "T_MergeJoin"], "content_hash": "0c7be6a944d02cd7abec2b7a39556a5320feae98bb255ca6646f9ba4408c1445", "versions": {"10": {"facts": [{"label": "\u6838\u5fc3\u8282\u70b9\u6807\u7b7e", "value": "T_MergeJoin"}, {"label": "\u7ed3\u6784\u5316 EXPLAIN \u8282\u70b9\u7c7b\u578b", "value": "Merge Join"}, {"label": "\u8f93\u5165", "value": "\u6709\u5e8f\u7684\u5916\u4fa7\u548c\u5185\u4fa7\u5b50\u8ba1\u5212"}, {"label": "\u8f93\u51fa", "value": "\u6309\u6240\u9009\u8fde\u63a5\u7c7b\u578b\u751f\u6210\u7684\u8fde\u63a5\u5143\u7ec4"}, {"label": "\u6267\u884c\u5668\u521d\u59cb\u5316\u51fd\u6570", "value": "ExecInitMergeJoin"}, {"label": "\u5185\u5b58\u673a\u5236", "value": "unclassified"}], "memory": {"evidence": [{"url": "https://ftp.postgresql.org/pub/source/v10.23/postgresql-10.23.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "6243569c57308f37d4ee23e2a477cc19928bc6cce4511c556d66cbc39e0d7ef4", "archive_sha256": "94a4b2528372458e5662c18d406629266667c437198160a18cdfd2c4a4d6eee9"}], "mechanism": "unclassified", "description": "\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002", "source_notes": []}, "tables": [{"key": "explain-labels", "rows": [{"label": "Merge", "identity": "Merge Join"}], "title": "\u672c\u6784\u5efa\u4e2d\u7684 EXPLAIN \u6807\u7b7e", "columns": [{"key": "label", "label": "\u6587\u672c\u683c\u5f0f\u6807\u7b7e"}, {"key": "identity", "label": "\u7ed3\u6784\u5316\u8282\u70b9\u6807\u8bc6"}]}], "related": [{"url": "/wiki/sql/explain/?v=10", "label": "EXPLAIN"}, {"url": "/docs/10/using-explain.html", "label": "\u4f7f\u7528 EXPLAIN"}, {"url": "/docs/10/parallel-plans.html", "label": "\u5e76\u884c\u8ba1\u5212"}, {"url": "/wiki/guc/enable_mergejoin/?v=10", "label": "enable_mergejoin"}], "release": {"ref": "PostgreSQL 10.23 source archive", "label": "10.23", "major": "10", "channel": "historical", "revision": "94a4b2528372458e5662c18d406629266667c437198160a18cdfd2c4a4d6eee9", "source_url": "https://ftp.postgresql.org/pub/source/v10.23/postgresql-10.23.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "https://ftp.postgresql.org/pub/source/v10.23/postgresql-10.23.tar.bz2", "line": 924, "path": "src/backend/commands/explain.c", "label": "src/backend/commands/explain.c:924", "sha256": "a785298532047cfeda969e78c3597a343dc1c56d61ba85830b0f16a02a14b5a1", "archive_sha256": "94a4b2528372458e5662c18d406629266667c437198160a18cdfd2c4a4d6eee9"}, {"url": "https://ftp.postgresql.org/pub/source/v10.23/postgresql-10.23.tar.bz2", "line": 295, "path": "src/backend/executor/execProcnode.c", "label": "src/backend/executor/execProcnode.c:295", "sha256": "cea76648bb38ae55f18f989768bee1a4ee025691ceea0f86bccb29dcdc166acc", "archive_sha256": "94a4b2528372458e5662c18d406629266667c437198160a18cdfd2c4a4d6eee9"}, {"url": "https://ftp.postgresql.org/pub/source/v10.23/postgresql-10.23.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "6243569c57308f37d4ee23e2a477cc19928bc6cce4511c556d66cbc39e0d7ef4", "archive_sha256": "94a4b2528372458e5662c18d406629266667c437198160a18cdfd2c4a4d6eee9"}, {"url": "https://ftp.postgresql.org/pub/source/v10.23/postgresql-10.23.tar.bz2", "path": "src/include/nodes/plannodes.h", "label": "src/include/nodes/plannodes.h", "sha256": "d562c321108844798cd234303fffb618f13d4ee3f3a5ac79bfd963b077e47c22", "archive_sha256": "94a4b2528372458e5662c18d406629266667c437198160a18cdfd2c4a4d6eee9"}, {"url": "https://pg.center/docs/10/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 10.23 \u00b7 using-explain", "sha256": "a4b4304aedb0a2da0145cc7c35b03b319a5c7ee3df35a8ef84ab6d3a610f98f3", "language": "en", "original_url": "/docs/10/using-explain.html#USING-EXPLAIN-BASICS"}, {"url": "https://pg.center/docs/10/using-explain.html#USING-EXPLAIN-CAVEATS", "path": "using-explain.html", "label": "PostgreSQL 10.23 \u00b7 using-explain", "sha256": "a4b4304aedb0a2da0145cc7c35b03b319a5c7ee3df35a8ef84ab6d3a610f98f3", "language": "en", "original_url": "/docs/10/using-explain.html#USING-EXPLAIN-CAVEATS"}, {"url": "https://pg.center/docs/10/parallel-plans.html#PARALLEL-JOINS", "path": "parallel-plans.html", "label": "PostgreSQL 10.23 \u00b7 parallel-plans", "sha256": "cd37ed0ef7e2cf177707f50d9a7258574b4cefdcc087e6ee99a3bf377d960fcb", "language": "en", "original_url": "/docs/10/parallel-plans.html#PARALLEL-JOINS"}, {"url": "https://pg.center/docs/10/parallel-plans.html#PARALLEL-AGGREGATION", "path": "parallel-plans.html", "label": "PostgreSQL 10.23 \u00b7 parallel-plans", "sha256": "cd37ed0ef7e2cf177707f50d9a7258574b4cefdcc087e6ee99a3bf377d960fcb", "language": "en", "original_url": "/docs/10/parallel-plans.html#PARALLEL-AGGREGATION"}], "node_tag": "T_MergeJoin", "sections": [{"title": "EXPLAIN \u540d\u79f0\u4e0e\u5c5e\u6027", "paragraphs": ["\u7ed3\u6784\u5316\u683c\u5f0f\u4f7f\u7528\u4e0a\u8ff0 Node Type\u3002\u6587\u672c\u683c\u5f0f\u540d\u79f0\u8fd8\u53ef\u80fd\u5305\u542b\u64cd\u4f5c\u3001\u7b56\u7565\u3001\u8fde\u63a5\u7c7b\u578b\u3001\u626b\u63cf\u65b9\u5411\u6216\u805a\u5408\u9636\u6bb5\u5c5e\u6027\u3002", "\u6b64\u6e90\u7801\u8bb0\u5f55\u7684\u6587\u672c\u540d\u79f0\uff1aMerge.", "\u5e76\u884c\u611f\u77e5\u4e0e\u5e76\u884c\u5b89\u5168\u662f\u4e0d\u540c\u7684\u8ba1\u5212\u5c5e\u6027\u3002\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u5185\u8fd0\u884c\u7684\u8282\u70b9\u4e0d\u4e00\u5b9a\u662f\u5e76\u884c\u611f\u77e5\u8282\u70b9\u3002"]}, {"title": "\u5185\u5b58\u4e0e\u4e34\u65f6\u5b58\u50a8", "paragraphs": ["\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002"]}, {"title": "\u5e76\u884c\u6267\u884c\u4e0e\u8fd0\u884c\u4fe1\u606f\u91c7\u96c6", "paragraphs": ["\u4ee5\u4e0b\u6e90\u7801\u56de\u8c03\u53ef\u4ee5\u534f\u8c03\u6267\u884c\u6216\u6536\u96c6\u5de5\u4f5c\u8fdb\u7a0b\u7684\u6d4b\u91cf\u6570\u636e\u3002\u56de\u8c03\u5b58\u5728\u4e0d\u4ee3\u8868\u8be5\u8282\u70b9\u666e\u904d\u652f\u6301\u5171\u4eab\u5e76\u884c\u626b\u63cf\u6216\u5171\u4eab\u72b6\u6001\u3002", "\u6b64\u6784\u5efa\u7684\u56de\u8c03\uff1anone extracted from this node implementation."]}, {"title": "\u540c\u7248\u672c\u624b\u518c\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u8981\u6c42\u8f93\u5165\u6309\u8fde\u63a5\u952e\u6392\u5e8f\u3002\u6b64\u8ba1\u5212\u901a\u8fc7\u7d22\u5f15\u626b\u63cf\u6309\u987a\u5e8f\u8bfb\u53d6 tenk1\uff1b\u5bf9\u4e8e onek\uff0c\u5219\u503e\u5411\u4e8e\u987a\u5e8f\u626b\u63cf\u540e\u6392\u5e8f\uff0c\u56e0\u4e3a\u8be5\u8868\u8981\u8bbf\u95ee\u7684\u884c\u66f4\u591a\u3002\uff08\u5bf9\u5927\u91cf\u884c\u6392\u5e8f\u65f6\uff0c\u987a\u5e8f\u626b\u63cf\u52a0\u6392\u5e8f\u5e38\u5e38\u4f18\u4e8e\u7d22\u5f15\u626b\u63cf\uff0c\u56e0\u4e3a\u540e\u8005\u9700\u8981\u975e\u987a\u5e8f\u78c1\u76d8\u8bbf\u95ee\u3002\uff09", "\u5f52\u5e76\u8fde\u63a5\u7684\u6d4b\u91cf\u7ed3\u679c\u4e5f\u53ef\u80fd\u4ea7\u751f\u8bef\u5bfc\u3002\u82e5\u4e00\u4fa7\u8f93\u5165\u5df2\u8017\u5c3d\uff0c\u53e6\u4e00\u4fa7\u7684\u4e0b\u4e00\u4e2a\u952e\u503c\u53c8\u5927\u4e8e\u5df2\u8017\u5c3d\u8f93\u5165\u7684\u6700\u540e\u4e00\u4e2a\u952e\u503c\uff0c\u5c31\u4e0d\u4f1a\u518d\u6709\u5339\u914d\uff0c\u56e0\u6b64\u4f1a\u505c\u6b62\u8bfb\u53d6\u53e6\u4e00\u4fa7\u3002\u8fd9\u6837\u4fbf\u672a\u8bfb\u53d6\u8be5\u5b50\u8282\u70b9\u7684\u5168\u90e8\u884c\uff0c\u7c7b\u4f3c LIMIT \u7684\u60c5\u51b5\u3002\u53e6\u5916\uff0c\u5916\u4fa7\uff08\u7b2c\u4e00\u4e2a\uff09\u5b50\u8282\u70b9\u6709\u91cd\u590d\u952e\u503c\u65f6\uff0c\u5185\u4fa7\uff08\u7b2c\u4e8c\u4e2a\uff09\u5b50\u8282\u70b9\u4f1a\u56de\u9000\u5e76\u91cd\u65b0\u626b\u63cf\u5339\u914d\u8be5\u952e\u503c\u7684\u884c\u3002EXPLAIN ANALYZE \u4f1a\u5c06\u5185\u4fa7\u91cd\u590d\u8f93\u51fa\u7684\u884c\u8ba1\u4f5c\u989d\u5916\u7684\u771f\u5b9e\u884c\u3002\u56e0\u6b64\u5916\u4fa7\u91cd\u590d\u503c\u5f88\u591a\u65f6\uff0c\u5185\u4fa7\u8ba1\u5212\u8282\u70b9\u62a5\u544a\u7684\u5b9e\u9645\u884c\u6570\u53ef\u80fd\u663e\u8457\u8d85\u8fc7\u5185\u4fa7\u5173\u7cfb\u4e2d\u7684\u5b9e\u9645\u884c\u6570\u3002", "\u4e0e\u975e\u5e76\u884c\u8ba1\u5212\u4e00\u6837\uff0c\u9a71\u52a8\u8868\u53ef\u4ee5\u901a\u8fc7\u5d4c\u5957\u5faa\u73af\u3001\u54c8\u5e0c\u8fde\u63a5\u6216\u5f52\u5e76\u8fde\u63a5\u4e0e\u4e00\u4e2a\u6216\u591a\u4e2a\u5176\u4ed6\u8868\u8fde\u63a5\u3002\u8fde\u63a5\u7684\u5185\u4fa7\u53ef\u4ee5\u662f\u89c4\u5212\u5668\u652f\u6301\u7684\u4efb\u4f55\u7c7b\u578b\u7684\u975e\u5e76\u884c\u8ba1\u5212\uff0c\u53ea\u8981\u5b83\u80fd\u591f\u5b89\u5168\u5730\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u4e2d\u8fd0\u884c\u3002\u4f8b\u5982\uff0c\u5982\u679c\u9009\u62e9\u4e86\u5d4c\u5957\u5faa\u73af\u8fde\u63a5\uff0c\u5185\u4fa7\u8ba1\u5212\u53ef\u4ee5\u662f\u4e00\u4e2a\u7d22\u5f15\u626b\u63cf\uff0c\u7528\u6765\u67e5\u627e\u53d6\u81ea\u8fde\u63a5\u5916\u4fa7\u7684\u503c\u3002", "\u6bcf\u4e2a\u5de5\u4f5c\u8fdb\u7a0b\u90fd\u4f1a\u5b8c\u6574\u6267\u884c\u8fde\u63a5\u7684\u5185\u4fa7\u3002\u8fd9\u5bf9\u5d4c\u5957\u5faa\u73af\u901a\u5e38\u4e0d\u662f\u95ee\u9898\uff0c\u4f46\u5bf9\u4e8e\u54c8\u5e0c\u8fde\u63a5\u6216\u5f52\u5e76\u8fde\u63a5\uff0c\u53ef\u80fd\u6548\u7387\u4e0d\u9ad8\u3002\u4f8b\u5982\uff0c\u5bf9\u4e8e\u54c8\u5e0c\u8fde\u63a5\uff0c\u8fd9\u9879\u9650\u5236\u610f\u5473\u7740\u6bcf\u4e2a\u5de5\u4f5c\u8fdb\u7a0b\u90fd\u8981\u6784\u5efa\u4e00\u4e2a\u76f8\u540c\u7684 hash \u8868\u3002\u8fde\u63a5\u5c0f\u8868\u65f6\u8fd9\u6837\u505a\u6548\u679c\u5f88\u597d\uff0c\u4f46\u5185\u4fa7\u8868\u8f83\u5927\u65f6\u53ef\u80fd\u6548\u7387\u4e0d\u9ad8\u3002\u5bf9\u4e8e\u5f52\u5e76\u8fde\u63a5\uff0c\u8fd9\u53ef\u80fd\u610f\u5473\u7740\u6bcf\u4e2a\u5de5\u4f5c\u8fdb\u7a0b\u90fd\u8981\u5355\u72ec\u5bf9\u5185\u4fa7\u5173\u7cfb\u6392\u5e8f\uff0c\u800c\u8fd9\u53ef\u80fd\u5f88\u6162\u3002\u5f53\u7136\uff0c\u5982\u679c\u8fd9\u79cd\u5e76\u884c\u8ba1\u5212\u7684\u6548\u7387\u4e0d\u9ad8\uff0c\u67e5\u8be2\u89c4\u5212\u5668\u901a\u5e38\u4f1a\u6539\u9009\u5176\u4ed6\u8ba1\u5212\uff08\u53ef\u80fd\u662f\u4e0d\u4f7f\u7528\u5e76\u884c\u6267\u884c\u7684\u8ba1\u5212\uff09\u3002", "PostgreSQL \u901a\u8fc7\u5206\u4e24\u4e2a\u9636\u6bb5\u8fdb\u884c\u805a\u5408\u6765\u652f\u6301\u5e76\u884c\u805a\u5408\u3002\u9996\u5148\uff0c\u6bcf\u4e2a\u53c2\u4e0e\u67e5\u8be2\u5e76\u884c\u90e8\u5206\u7684\u8fdb\u7a0b\u6267\u884c\u4e00\u4e2a\u805a\u5408\u6b65\u9aa4\uff0c\u4e3a\u8be5\u8fdb\u7a0b\u6240\u89c1\u5230\u7684\u6bcf\u4e2a\u5206\u7ec4\u4ea7\u751f\u4e00\u4e2a\u90e8\u5206\u7ed3\u679c\u3002\u8fd9\u5728\u8ba1\u5212\u4e2d\u4f53\u73b0\u4e3a\u4e00\u4e2a Partial Aggregate \u8282\u70b9\u3002\u7136\u540e\uff0c\u90e8\u5206\u7ed3\u679c\u901a\u8fc7 Gather \u6216 Gather Merge \u4f20\u9001\u7ed9\u9886\u5bfc\u8005\u3002\u6700\u540e\uff0c\u9886\u5bfc\u8005\u4f1a\u628a\u6765\u81ea\u6240\u6709\u5de5\u4f5c\u8fdb\u7a0b\u7684\u7ed3\u679c\u518d\u6b21\u805a\u5408\uff0c\u4ee5\u4ea7\u751f\u6700\u7ec8\u7ed3\u679c\u3002\u8fd9\u5728\u8ba1\u5212\u4e2d\u4f53\u73b0\u4e3a\u4e00\u4e2a Finalize Aggregate \u8282\u70b9\u3002"]}, {"title": "\u672c\u7248\u624b\u518c\u4e2d\u7684\u793a\u4f8b", "blocks": [{"code": "EXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=198.11..268.19 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..656.28 rows=101 width=244)\n         Filter: (unique1 < 100)\n   ->  Sort  (cost=197.83..200.33 rows=1000 width=244)\n         Sort Key: t2.unique2\n         ->  Seq Scan on onek t2  (cost=0.00..148.00 rows=1000 width=244)", "source": {"url": "/docs/10/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 10.23 \u00b7 using-explain", "sha256": "a4b4304aedb0a2da0145cc7c35b03b319a5c7ee3df35a8ef84ab6d3a610f98f3"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 10.23 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u53e6\u4e00\u79cd\u53ef\u80fd\u7684\u8fde\u63a5\u65b9\u5f0f\u662f\u5f52\u5e76\u8fde\u63a5\uff0c\u5982\u4e0b\u6240\u793a\uff1a"]}, {"code": "SET enable_sort = off;\n\nEXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=0.56..292.65 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..656.28 rows=101 width=244)\n         Filter: (unique1 < 100)\n   ->  Index Scan using onek_unique2 on onek t2  (cost=0.28..224.79 rows=1000 width=244)", "source": {"url": "/docs/10/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 10.23 \u00b7 using-explain", "sha256": "a4b4304aedb0a2da0145cc7c35b03b319a5c7ee3df35a8ef84ab6d3a610f98f3"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 10.23 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u89c2\u5bdf\u5907\u9009\u8ba1\u5212\u7684\u4e00\u79cd\u529e\u6cd5\uff0c\u662f\u4f7f\u7528\u7b2c 19.7.1 \u8282\u7684\u542f\u7528\uff0f\u7981\u7528\u6807\u5fd7\uff0c\u5f3a\u5236\u89c4\u5212\u5668\u5ffd\u7565\u5b83\u8ba4\u4e3a\u4ee3\u4ef7\u6700\u4f4e\u7684\u7b56\u7565\u3002\u8fd9\u79cd\u5de5\u5177\u8f83\u4e3a\u7c97\u7565\uff0c\u4f46\u5f88\u6709\u7528\uff0c\u53e6\u89c1\u7b2c 14.3 \u8282\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4e0d\u786e\u5b9a\u524d\u4f8b\u4e2d\u5bf9 onek \u8868\u91c7\u7528\u987a\u5e8f\u626b\u63cf\u518d\u6392\u5e8f\u662f\u5426\u6700\u4f73\uff0c\u53ef\u4ee5\u5c1d\u8bd5\uff1a"]}]}, {"title": "\u6267\u884c\u5668\u5b9e\u73b0\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u5bf9\u6ee1\u8db3 ((= outerKey innerKey) ...) \u5f62\u5f0f\u8fde\u63a5\u6761\u4ef6\u7684\u5185\u5916\u4fa7\u5143\u7ec4\u6267\u884c\u8fde\u63a5\u3002\u8fde\u63a5\u6761\u4ef6\u5217\u8868\u7531\u67e5\u8be2\u89c4\u5212\u5668\u63d0\u4f9b\uff0c\u53ef\u4ee5\u5305\u542b\u591a\u4e2a (= outerKey innerKey) \u6761\u4ef6\uff0c\u4ee5\u652f\u6301\u590d\u5408\u6392\u5e8f\u952e\u3002", "\u4e0d\u8fc7\uff0c\u67e5\u8be2\u6267\u884c\u5668\u9700\u8981\u5224\u65ad\u5916\u4fa7\u5143\u7ec4\u662f\u5426\u201c\u5927\u4e8e\uff0f\u5c0f\u4e8e\u201d\u5185\u4fa7\u5143\u7ec4\uff0c\u4ee5\u4fbf\u201c\u540c\u6b65\u201d\u4e24\u4e2a\u5173\u7cfb\u3002\u4f8b\u5982\uff0c\u8003\u8651\u4ee5\u4e0b\u5173\u7cfb\uff1a", "outer: (0 ^1 1 2 5 5 5 6 6 7) current tuple: 1 inner: (1 ^3 5 5 5 5 6) current tuple: 3", "\u4e3a\u7ee7\u7eed\u5f52\u5e76\u8fde\u63a5\uff0c\u6267\u884c\u5668\u9700\u8981\u626b\u63cf\u5185\u5916\u4fa7\u5173\u7cfb\uff0c\u76f4\u5230\u627e\u5230\u5339\u914d\u7684\u5143\u7ec4 5\u3002\u5b83\u9700\u8981\u77e5\u9053\u5f53\u524d\u5185\u4fa7\u5143\u7ec4 3\u201c\u5927\u4e8e\u201d\u5916\u4fa7\u5143\u7ec4 1\uff0c\u56e0\u6b64\u5e94\u5148\u626b\u63cf\u5916\u4fa7\u5173\u7cfb\u4ee5\u5bfb\u627e\u5339\u914d\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002", "\u56e0\u6b64\uff0c\u4e0d\u76f4\u63a5\u6267\u884c\u5f52\u5e76\u8fde\u63a5\u6761\u4ef6\uff0c\u800c\u662f\u5206\u522b\u6c42\u503c\u5de6\u53f3\u952e\u8868\u8fbe\u5f0f\uff0c\u518d\u9010\u5217\u6bd4\u8f83\uff08\u53c2\u89c1 MJCompare\uff09\u3002\u89c4\u5212\u5668\u63d0\u4f9b\u8db3\u591f\u7684\u8f93\u5165\u6392\u5e8f\u4fe1\u606f\uff0c\u8ba9\u6267\u884c\u5668\u786e\u5b9a\u6bd4\u8f83\u65b9\u6cd5\u3002\u53ef\u4ee5\u4f7f\u7528\u76f8\u5e94\u7684 B-tree \u6bd4\u8f83\u51fd\u6570\uff0c\u56e0\u4e3a Postgres \u7684\u6392\u5e8f\u8bed\u4e49\u4ec5\u7531 B-tree \u64cd\u4f5c\u7b26\u5bb6\u65cf\u5b9a\u4e49\u3002"]}, {"code": "case T_MergeJoin:\n\t\t\tpname = \"Merge\";\t/* \"Join\" gets added by jointype switch */\n\t\t\tsname = \"Merge Join\";\n\t\t\tbreak;", "title": "\u6838\u5fc3\u6e90\u7801\u4e2d\u7684 EXPLAIN \u6807\u8bc6"}], "strategies": [], "description": ["\u4f7f\u7528\u5f52\u5e76\u6761\u4ef6\u8fde\u63a5\u6709\u5e8f\u8f93\u5165\u6d41\u3002"], "localization": {"status": "complete", "sources": [{"url": "/docs/10/parallel-plans.html", "method": "same-major semantic node", "sha256": "885d4ceb10c77809e522baf5c18257546222c5ed3bdeba157ab2356fd6b1cdc7", "language": "zh", "matched_nodes": ["#PARALLEL-PLANS/div[4]/p[1]", "#PARALLEL-PLANS/div[4]/p[2]", "#PARALLEL-PLANS/div[5]/p[1]"]}], "language": "zh", "original_text": {"/versions/10/description/0": "Joins ordered input streams using merge clauses.", "/versions/10/facts/0/label": "Core node tag", "/versions/10/facts/1/label": "Structured EXPLAIN Node Type", "/versions/10/facts/2/label": "Inputs", "/versions/10/facts/2/value": "Ordered outer and inner child plans", "/versions/10/facts/3/label": "Output", "/versions/10/facts/3/value": "Joined tuples according to the selected join type", "/versions/10/facts/4/label": "Executor initializer", "/versions/10/facts/5/label": "Memory mechanism", "/versions/10/tables/0/title": "EXPLAIN labels in this source build", "/versions/10/related/1/label": "Using EXPLAIN", "/versions/10/related/2/label": "Parallel plans", "/versions/10/sections/0/title": "EXPLAIN names and attributes", "/versions/10/sections/1/title": "Memory and temporary storage", "/versions/10/sections/2/title": "Parallel execution and instrumentation", "/versions/10/sections/3/title": "Same-version manual discussion", "/versions/10/sections/4/title": "Examples from this manual build", "/versions/10/sections/5/title": "Executor implementation notes", "/versions/10/sections/6/title": "EXPLAIN identity in core source", "/versions/10/memory/description": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/10/sections/0/paragraphs/0": "Structured formats use the Node Type above. Text-format spellings can also include operation, strategy, join type, scan direction or aggregation-stage attributes.", "/versions/10/sections/0/paragraphs/1": "Text names recorded by this source: Merge.", "/versions/10/sections/0/paragraphs/2": "Parallel-aware and parallel-safe are different plan properties. A node running inside a parallel worker is not necessarily a parallel-aware node.", "/versions/10/sections/1/paragraphs/0": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/10/sections/2/paragraphs/0": "The source callbacks below can coordinate execution or collect worker instrumentation. Their presence is not a blanket claim that this node supports a shared parallel scan or shared state.", "/versions/10/sections/2/paragraphs/1": "Callbacks in this build: none extracted from this node implementation.", "/versions/10/sections/3/paragraphs/0": "Merge join requires its input data to be sorted on the join keys. In this plan the tenk1 data is sorted by using an index scan to visit the rows in the correct order, but a sequential scan and sort is preferred for onek , because there are many more rows to be visited in that table. (Sequential-scan-and-sort frequently beats an index scan for sorting many rows, because of the nonsequential disk access required by the index scan.)", "/versions/10/sections/3/paragraphs/1": "Merge joins also have measurement artifacts that can confuse the unwary. A merge join will stop reading one input if it's exhausted the other input and the next key value in the one input is greater than the last key value of the other input; in such a case there can be no more matches and so no need to scan the rest of the first input. This results in not reading all of one child, with results like those mentioned for LIMIT . Also, if the outer (first) child contains rows with duplicate key values, the inner (second) child is backed up and rescanned for the portion of its rows matching that key value. EXPLAIN ANALYZE counts these repeated emissions of the same inner rows as if they were real additional rows. When there are many outer duplicates, the reported actual row count for the inner child plan node can be significantly larger than the number of rows that are actually in the inner relation.", "/versions/10/sections/3/paragraphs/2": "Just as in a non-parallel plan, the driving table may be joined to one or more other tables using a nested loop, hash join, or merge join. The inner side of the join may be any kind of non-parallel plan that is otherwise supported by the planner provided that it is safe to run within a parallel worker. For example, if a nested loop join is chosen, the inner plan may be an index scan which looks up a value taken from the outer side of the join.", "/versions/10/sections/3/paragraphs/3": "Each worker will execute the inner side of the join in full. This is typically not a problem for nested loops, but may be inefficient for cases involving hash or merge joins. For example, for a hash join, this restriction means that an identical hash table is built in each worker process, which works fine for joins against small tables but may not be efficient when the inner table is large. For a merge join, it might mean that each worker performs a separate sort of the inner relation, which could be slow. Of course, in cases where a parallel plan of this type would be inefficient, the query planner will normally choose some other plan (possibly one which does not use parallelism) instead.", "/versions/10/sections/3/paragraphs/4": "PostgreSQL supports parallel aggregation by aggregating in two stages. First, each process participating in the parallel portion of the query performs an aggregation step, producing a partial result for each group of which that process is aware. This is reflected in the plan as a Partial Aggregate node. Second, the partial results are transferred to the leader via Gather or Gather Merge . Finally, the leader re-aggregates the results across all workers in order to produce the final result. This is reflected in the plan as a Finalize Aggregate node.", "/versions/10/sections/5/paragraphs/0": "Merge-join is done by joining the inner and outer tuples satisfying join clauses of the form ((= outerKey innerKey) ...). The join clause list is provided by the query planner and may contain more than one (= outerKey innerKey) clause (for composite sort key).", "/versions/10/sections/5/paragraphs/1": "However, the query executor needs to know whether an outer tuple is \"greater/smaller\" than an inner tuple so that it can \"synchronize\" the two relations. For example, consider the following relations:", "/versions/10/sections/5/paragraphs/3": "To continue the merge-join, the executor needs to scan both inner and outer relations till the matching tuples 5. It needs to know that currently inner tuple 3 is \"greater\" than outer tuple 1 and therefore it should scan the outer relation first to find a matching tuple and so on.", "/versions/10/sections/5/paragraphs/4": "Therefore, rather than directly executing the merge join clauses, we evaluate the left and right key expressions separately and then compare the columns one at a time (see MJCompare). The planner passes us enough information about the sort ordering of the inputs to allow us to determine how to make the comparison. We may use the appropriate btree comparison function, since Postgres' only notion of ordering is specified by btree opfamilies.", "/versions/10/tables/0/columns/0/label": "Text-format label", "/versions/10/tables/0/columns/1/label": "Structured node identity", "/versions/10/sections/4/blocks/0/paragraphs/0": "Example copied from the PostgreSQL 10.23 manual; it was not executed for this collection.", "/versions/10/sections/4/blocks/0/paragraphs/1": "Another possible type of join is a merge join, illustrated here:", "/versions/10/sections/4/blocks/1/paragraphs/0": "Example copied from the PostgreSQL 10.23 manual; it was not executed for this collection.", "/versions/10/sections/4/blocks/1/paragraphs/1": "One way to look at variant plans is to force the planner to disregard whatever strategy it thought was the cheapest, using the enable/disable flags described in Section 19.7.1 . (This is a crude tool, but useful. See also Section 14.3 .) For example, if we're unconvinced that sequential-scan-and-sort is the best way to deal with table onek in the previous example, we could try"}, "fallback_fields": [], "source_language": "en", "original_snapshot_sha256": "03ca867fd01908286b6da594e8787125290fd0482601923699d8b94a3ae6d16f"}, "evidence_kind": "source and documentation", "explain_names": ["Merge"], "partial_modes": [], "comparison_data": {"node_tag": "T_MergeJoin", "strategies": [], "text_names": ["Merge"], "initializer": "ExecInitMergeJoin", "partial_modes": [], "memory_mechanism": "unclassified", "parallel_callbacks": []}, "comparison_hash": "b17771ee4d48585afbaba91552e5eb00f05a4b6784aa491387217937a4a30511", "explain_prefixes": ["Parallel"], "runtime_verified": false, "source_inventory": {"explain": "src/backend/commands/explain.c", "executor": "src/backend/executor/execProcnode.c", "implementation": "src/backend/executor/nodeMergejoin.c"}, "parallel_callbacks": []}, "11": {"facts": [{"label": "\u6838\u5fc3\u8282\u70b9\u6807\u7b7e", "value": "T_MergeJoin"}, {"label": "\u7ed3\u6784\u5316 EXPLAIN \u8282\u70b9\u7c7b\u578b", "value": "Merge Join"}, {"label": "\u8f93\u5165", "value": "\u6709\u5e8f\u7684\u5916\u4fa7\u548c\u5185\u4fa7\u5b50\u8ba1\u5212"}, {"label": "\u8f93\u51fa", "value": "\u6309\u6240\u9009\u8fde\u63a5\u7c7b\u578b\u751f\u6210\u7684\u8fde\u63a5\u5143\u7ec4"}, {"label": "\u6267\u884c\u5668\u521d\u59cb\u5316\u51fd\u6570", "value": "ExecInitMergeJoin"}, {"label": "\u5185\u5b58\u673a\u5236", "value": "unclassified"}], "memory": {"evidence": [{"url": "https://ftp.postgresql.org/pub/source/v11.22/postgresql-11.22.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "43151ca42279b11ec4428fb349dd66ee12a7a114376ff44ac1b0031fa2c5213a", "archive_sha256": "2cb7c97d7a0d7278851bbc9c61f467b69c094c72b81740b751108e7892ebe1f0"}], "mechanism": "unclassified", "description": "\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002", "source_notes": []}, "tables": [{"key": "explain-labels", "rows": [{"label": "Merge", "identity": "Merge Join"}], "title": "\u672c\u6784\u5efa\u4e2d\u7684 EXPLAIN \u6807\u7b7e", "columns": [{"key": "label", "label": "\u6587\u672c\u683c\u5f0f\u6807\u7b7e"}, {"key": "identity", "label": "\u7ed3\u6784\u5316\u8282\u70b9\u6807\u8bc6"}]}], "related": [{"url": "/wiki/sql/explain/?v=11", "label": "EXPLAIN"}, {"url": "/docs/11/using-explain.html", "label": "\u4f7f\u7528 EXPLAIN"}, {"url": "/docs/11/parallel-plans.html", "label": "\u5e76\u884c\u8ba1\u5212"}, {"url": "/wiki/guc/enable_mergejoin/?v=11", "label": "enable_mergejoin"}], "release": {"ref": "PostgreSQL 11.22 source archive", "label": "11.22", "major": "11", "channel": "historical", "revision": "2cb7c97d7a0d7278851bbc9c61f467b69c094c72b81740b751108e7892ebe1f0", "source_url": "https://ftp.postgresql.org/pub/source/v11.22/postgresql-11.22.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "https://ftp.postgresql.org/pub/source/v11.22/postgresql-11.22.tar.bz2", "line": 1049, "path": "src/backend/commands/explain.c", "label": "src/backend/commands/explain.c:1049", "sha256": "9df8400c1a4377179572ceb916d6020fca4e2760f74bf416d77ed97476523bbd", "archive_sha256": "2cb7c97d7a0d7278851bbc9c61f467b69c094c72b81740b751108e7892ebe1f0"}, {"url": "https://ftp.postgresql.org/pub/source/v11.22/postgresql-11.22.tar.bz2", "line": 295, "path": "src/backend/executor/execProcnode.c", "label": "src/backend/executor/execProcnode.c:295", "sha256": "95ef4d4a5df4c29f14af9763fae2c530449bdacdf3853d9ff297adf1fed6153b", "archive_sha256": "2cb7c97d7a0d7278851bbc9c61f467b69c094c72b81740b751108e7892ebe1f0"}, {"url": "https://ftp.postgresql.org/pub/source/v11.22/postgresql-11.22.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "43151ca42279b11ec4428fb349dd66ee12a7a114376ff44ac1b0031fa2c5213a", "archive_sha256": "2cb7c97d7a0d7278851bbc9c61f467b69c094c72b81740b751108e7892ebe1f0"}, {"url": "https://ftp.postgresql.org/pub/source/v11.22/postgresql-11.22.tar.bz2", "path": "src/include/nodes/plannodes.h", "label": "src/include/nodes/plannodes.h", "sha256": "5e0511194183800e8d6eb293fd4b40639c7d3118e2d199c8e7865ba4fa4cf67f", "archive_sha256": "2cb7c97d7a0d7278851bbc9c61f467b69c094c72b81740b751108e7892ebe1f0"}, {"url": "https://pg.center/docs/11/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 11.22 \u00b7 using-explain", "sha256": "8411bc78085d4737e32d7cca103d859da6c6539e33ec5e2fba46e74c6f199d8a", "language": "en", "original_url": "/docs/11/using-explain.html#USING-EXPLAIN-BASICS"}, {"url": "https://pg.center/docs/11/using-explain.html#USING-EXPLAIN-CAVEATS", "path": "using-explain.html", "label": "PostgreSQL 11.22 \u00b7 using-explain", "sha256": "8411bc78085d4737e32d7cca103d859da6c6539e33ec5e2fba46e74c6f199d8a", "language": "en", "original_url": "/docs/11/using-explain.html#USING-EXPLAIN-CAVEATS"}, {"url": "https://pg.center/docs/11/parallel-plans.html#PARALLEL-JOINS", "path": "parallel-plans.html", "label": "PostgreSQL 11.22 \u00b7 parallel-plans", "sha256": "353df5869034b7665159a74037d9cf3e1800d15efcea3390daaa99aae89fa288", "language": "en", "original_url": "/docs/11/parallel-plans.html#PARALLEL-JOINS"}, {"url": "https://pg.center/docs/11/parallel-plans.html#PARALLEL-AGGREGATION", "path": "parallel-plans.html", "label": "PostgreSQL 11.22 \u00b7 parallel-plans", "sha256": "353df5869034b7665159a74037d9cf3e1800d15efcea3390daaa99aae89fa288", "language": "en", "original_url": "/docs/11/parallel-plans.html#PARALLEL-AGGREGATION"}], "node_tag": "T_MergeJoin", "sections": [{"title": "EXPLAIN \u540d\u79f0\u4e0e\u5c5e\u6027", "paragraphs": ["\u7ed3\u6784\u5316\u683c\u5f0f\u4f7f\u7528\u4e0a\u8ff0 Node Type\u3002\u6587\u672c\u683c\u5f0f\u540d\u79f0\u8fd8\u53ef\u80fd\u5305\u542b\u64cd\u4f5c\u3001\u7b56\u7565\u3001\u8fde\u63a5\u7c7b\u578b\u3001\u626b\u63cf\u65b9\u5411\u6216\u805a\u5408\u9636\u6bb5\u5c5e\u6027\u3002", "\u6b64\u6e90\u7801\u8bb0\u5f55\u7684\u6587\u672c\u540d\u79f0\uff1aMerge.", "\u5e76\u884c\u611f\u77e5\u4e0e\u5e76\u884c\u5b89\u5168\u662f\u4e0d\u540c\u7684\u8ba1\u5212\u5c5e\u6027\u3002\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u5185\u8fd0\u884c\u7684\u8282\u70b9\u4e0d\u4e00\u5b9a\u662f\u5e76\u884c\u611f\u77e5\u8282\u70b9\u3002"]}, {"title": "\u5185\u5b58\u4e0e\u4e34\u65f6\u5b58\u50a8", "paragraphs": ["\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002"]}, {"title": "\u5e76\u884c\u6267\u884c\u4e0e\u8fd0\u884c\u4fe1\u606f\u91c7\u96c6", "paragraphs": ["\u4ee5\u4e0b\u6e90\u7801\u56de\u8c03\u53ef\u4ee5\u534f\u8c03\u6267\u884c\u6216\u6536\u96c6\u5de5\u4f5c\u8fdb\u7a0b\u7684\u6d4b\u91cf\u6570\u636e\u3002\u56de\u8c03\u5b58\u5728\u4e0d\u4ee3\u8868\u8be5\u8282\u70b9\u666e\u904d\u652f\u6301\u5171\u4eab\u5e76\u884c\u626b\u63cf\u6216\u5171\u4eab\u72b6\u6001\u3002", "\u6b64\u6784\u5efa\u7684\u56de\u8c03\uff1anone extracted from this node implementation."]}, {"title": "\u540c\u7248\u672c\u624b\u518c\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u8981\u6c42\u8f93\u5165\u6309\u8fde\u63a5\u952e\u6392\u5e8f\u3002\u6b64\u8ba1\u5212\u901a\u8fc7\u7d22\u5f15\u626b\u63cf\u6309\u987a\u5e8f\u8bfb\u53d6 tenk1\uff1b\u5bf9\u4e8e onek\uff0c\u5219\u503e\u5411\u4e8e\u987a\u5e8f\u626b\u63cf\u540e\u6392\u5e8f\uff0c\u56e0\u4e3a\u8be5\u8868\u8981\u8bbf\u95ee\u7684\u884c\u66f4\u591a\u3002\uff08\u5bf9\u5927\u91cf\u884c\u6392\u5e8f\u65f6\uff0c\u987a\u5e8f\u626b\u63cf\u52a0\u6392\u5e8f\u5e38\u5e38\u4f18\u4e8e\u7d22\u5f15\u626b\u63cf\uff0c\u56e0\u4e3a\u540e\u8005\u9700\u8981\u975e\u987a\u5e8f\u78c1\u76d8\u8bbf\u95ee\u3002\uff09", "\u5f52\u5e76\u8fde\u63a5\u7684\u6d4b\u91cf\u7ed3\u679c\u4e5f\u53ef\u80fd\u4ea7\u751f\u8bef\u5bfc\u3002\u82e5\u4e00\u4fa7\u8f93\u5165\u5df2\u8017\u5c3d\uff0c\u53e6\u4e00\u4fa7\u7684\u4e0b\u4e00\u4e2a\u952e\u503c\u53c8\u5927\u4e8e\u5df2\u8017\u5c3d\u8f93\u5165\u7684\u6700\u540e\u4e00\u4e2a\u952e\u503c\uff0c\u5c31\u4e0d\u4f1a\u518d\u6709\u5339\u914d\uff0c\u56e0\u6b64\u4f1a\u505c\u6b62\u8bfb\u53d6\u53e6\u4e00\u4fa7\u3002\u8fd9\u6837\u4fbf\u672a\u8bfb\u53d6\u8be5\u5b50\u8282\u70b9\u7684\u5168\u90e8\u884c\uff0c\u7c7b\u4f3c LIMIT \u7684\u60c5\u51b5\u3002\u53e6\u5916\uff0c\u5916\u4fa7\uff08\u7b2c\u4e00\u4e2a\uff09\u5b50\u8282\u70b9\u6709\u91cd\u590d\u952e\u503c\u65f6\uff0c\u5185\u4fa7\uff08\u7b2c\u4e8c\u4e2a\uff09\u5b50\u8282\u70b9\u4f1a\u56de\u9000\u5e76\u91cd\u65b0\u626b\u63cf\u5339\u914d\u8be5\u952e\u503c\u7684\u884c\u3002EXPLAIN ANALYZE \u4f1a\u5c06\u5185\u4fa7\u91cd\u590d\u8f93\u51fa\u7684\u884c\u8ba1\u4f5c\u989d\u5916\u7684\u771f\u5b9e\u884c\u3002\u56e0\u6b64\u5916\u4fa7\u91cd\u590d\u503c\u5f88\u591a\u65f6\uff0c\u5185\u4fa7\u8ba1\u5212\u8282\u70b9\u62a5\u544a\u7684\u5b9e\u9645\u884c\u6570\u53ef\u80fd\u663e\u8457\u8d85\u8fc7\u5185\u4fa7\u5173\u7cfb\u4e2d\u7684\u5b9e\u9645\u884c\u6570\u3002", "\u4e0e\u975e\u5e76\u884c\u8ba1\u5212\u4e00\u6837\uff0c\u9a71\u52a8\u8868\u53ef\u4ee5\u901a\u8fc7\u5d4c\u5957\u5faa\u73af\u3001\u54c8\u5e0c\u8fde\u63a5\u6216\u5f52\u5e76\u8fde\u63a5\u4e0e\u4e00\u4e2a\u6216\u591a\u4e2a\u5176\u4ed6\u8868\u8fde\u63a5\u3002\u8fde\u63a5\u7684\u5185\u4fa7\u53ef\u4ee5\u662f\u89c4\u5212\u5668\u652f\u6301\u7684\u4efb\u4f55\u7c7b\u578b\u7684\u975e\u5e76\u884c\u8ba1\u5212\uff0c\u53ea\u8981\u5b83\u80fd\u591f\u5b89\u5168\u5730\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u4e2d\u8fd0\u884c\u3002\u6839\u636e\u8fde\u63a5\u7c7b\u578b\uff0c\u5185\u4fa7\u4e5f\u53ef\u4ee5\u662f\u5e76\u884c\u8ba1\u5212\u3002", "\u5728 \u5f52\u5e76\u8fde\u63a5 \u4e2d\uff0c\u5185\u4fa7\u59cb\u7ec8\u662f\u975e\u5e76\u884c\u8ba1\u5212\uff0c\u56e0\u6b64\u4f1a\u88ab\u5b8c\u6574\u6267\u884c\u3002\u8fd9\u53ef\u80fd\u6548\u7387\u4e0d\u9ad8\uff0c\u5c24\u5176\u662f\u5728\u5fc5\u987b\u6267\u884c\u6392\u5e8f\u65f6\uff0c\u56e0\u4e3a\u5de5\u4f5c\u91cf\u548c\u7ed3\u679c\u6570\u636e\u4f1a\u5728\u6bcf\u4e2a\u534f\u4f5c\u8fdb\u7a0b\u4e2d\u91cd\u590d\u3002", "PostgreSQL \u901a\u8fc7\u5206\u4e24\u4e2a\u9636\u6bb5\u8fdb\u884c\u805a\u5408\u6765\u652f\u6301\u5e76\u884c\u805a\u5408\u3002\u9996\u5148\uff0c\u6bcf\u4e2a\u53c2\u4e0e\u67e5\u8be2\u5e76\u884c\u90e8\u5206\u7684\u8fdb\u7a0b\u6267\u884c\u4e00\u4e2a\u805a\u5408\u6b65\u9aa4\uff0c\u4e3a\u8be5\u8fdb\u7a0b\u6240\u89c1\u5230\u7684\u6bcf\u4e2a\u5206\u7ec4\u4ea7\u751f\u4e00\u4e2a\u90e8\u5206\u7ed3\u679c\u3002\u8fd9\u5728\u8ba1\u5212\u4e2d\u4f53\u73b0\u4e3a\u4e00\u4e2a Partial Aggregate \u8282\u70b9\u3002\u7136\u540e\uff0c\u90e8\u5206\u7ed3\u679c\u901a\u8fc7 Gather \u6216 Gather Merge \u4f20\u9001\u7ed9\u9886\u5bfc\u8005\u3002\u6700\u540e\uff0c\u9886\u5bfc\u8005\u4f1a\u628a\u6765\u81ea\u6240\u6709\u5de5\u4f5c\u8fdb\u7a0b\u7684\u7ed3\u679c\u518d\u6b21\u805a\u5408\uff0c\u4ee5\u4ea7\u751f\u6700\u7ec8\u7ed3\u679c\u3002\u8fd9\u5728\u8ba1\u5212\u4e2d\u4f53\u73b0\u4e3a\u4e00\u4e2a Finalize Aggregate \u8282\u70b9\u3002"]}, {"title": "\u672c\u7248\u624b\u518c\u4e2d\u7684\u793a\u4f8b", "blocks": [{"code": "EXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=198.11..268.19 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..656.28 rows=101 width=244)\n         Filter: (unique1 < 100)\n   ->  Sort  (cost=197.83..200.33 rows=1000 width=244)\n         Sort Key: t2.unique2\n         ->  Seq Scan on onek t2  (cost=0.00..148.00 rows=1000 width=244)", "source": {"url": "/docs/11/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 11.22 \u00b7 using-explain", "sha256": "8411bc78085d4737e32d7cca103d859da6c6539e33ec5e2fba46e74c6f199d8a"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 11.22 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u53e6\u4e00\u79cd\u53ef\u80fd\u7684\u8fde\u63a5\u65b9\u5f0f\u662f\u5f52\u5e76\u8fde\u63a5\uff0c\u5982\u4e0b\u6240\u793a\uff1a"]}, {"code": "SET enable_sort = off;\n\nEXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=0.56..292.65 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..656.28 rows=101 width=244)\n         Filter: (unique1 < 100)\n   ->  Index Scan using onek_unique2 on onek t2  (cost=0.28..224.79 rows=1000 width=244)", "source": {"url": "/docs/11/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 11.22 \u00b7 using-explain", "sha256": "8411bc78085d4737e32d7cca103d859da6c6539e33ec5e2fba46e74c6f199d8a"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 11.22 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u89c2\u5bdf\u5907\u9009\u8ba1\u5212\u7684\u4e00\u79cd\u529e\u6cd5\uff0c\u662f\u4f7f\u7528\u7b2c 19.7.1 \u8282\u7684\u542f\u7528\uff0f\u7981\u7528\u6807\u5fd7\uff0c\u5f3a\u5236\u89c4\u5212\u5668\u5ffd\u7565\u5b83\u8ba4\u4e3a\u4ee3\u4ef7\u6700\u4f4e\u7684\u7b56\u7565\u3002\u8fd9\u79cd\u5de5\u5177\u8f83\u4e3a\u7c97\u7565\uff0c\u4f46\u5f88\u6709\u7528\uff0c\u53e6\u89c1\u7b2c 14.3 \u8282\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4e0d\u786e\u5b9a\u524d\u4f8b\u4e2d\u5bf9 onek \u8868\u91c7\u7528\u987a\u5e8f\u626b\u63cf\u518d\u6392\u5e8f\u662f\u5426\u6700\u4f73\uff0c\u53ef\u4ee5\u5c1d\u8bd5\uff1a"]}]}, {"title": "\u6267\u884c\u5668\u5b9e\u73b0\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u5bf9\u6ee1\u8db3 ((= outerKey innerKey) ...) \u5f62\u5f0f\u8fde\u63a5\u6761\u4ef6\u7684\u5185\u5916\u4fa7\u5143\u7ec4\u6267\u884c\u8fde\u63a5\u3002\u8fde\u63a5\u6761\u4ef6\u5217\u8868\u7531\u67e5\u8be2\u89c4\u5212\u5668\u63d0\u4f9b\uff0c\u53ef\u4ee5\u5305\u542b\u591a\u4e2a (= outerKey innerKey) \u6761\u4ef6\uff0c\u4ee5\u652f\u6301\u590d\u5408\u6392\u5e8f\u952e\u3002", "\u4e0d\u8fc7\uff0c\u67e5\u8be2\u6267\u884c\u5668\u9700\u8981\u5224\u65ad\u5916\u4fa7\u5143\u7ec4\u662f\u5426\u201c\u5927\u4e8e\uff0f\u5c0f\u4e8e\u201d\u5185\u4fa7\u5143\u7ec4\uff0c\u4ee5\u4fbf\u201c\u540c\u6b65\u201d\u4e24\u4e2a\u5173\u7cfb\u3002\u4f8b\u5982\uff0c\u8003\u8651\u4ee5\u4e0b\u5173\u7cfb\uff1a", "outer: (0 ^1 1 2 5 5 5 6 6 7) current tuple: 1 inner: (1 ^3 5 5 5 5 6) current tuple: 3", "\u4e3a\u7ee7\u7eed\u5f52\u5e76\u8fde\u63a5\uff0c\u6267\u884c\u5668\u9700\u8981\u626b\u63cf\u5185\u5916\u4fa7\u5173\u7cfb\uff0c\u76f4\u5230\u627e\u5230\u5339\u914d\u7684\u5143\u7ec4 5\u3002\u5b83\u9700\u8981\u77e5\u9053\u5f53\u524d\u5185\u4fa7\u5143\u7ec4 3\u201c\u5927\u4e8e\u201d\u5916\u4fa7\u5143\u7ec4 1\uff0c\u56e0\u6b64\u5e94\u5148\u626b\u63cf\u5916\u4fa7\u5173\u7cfb\u4ee5\u5bfb\u627e\u5339\u914d\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002", "\u56e0\u6b64\uff0c\u4e0d\u76f4\u63a5\u6267\u884c\u5f52\u5e76\u8fde\u63a5\u6761\u4ef6\uff0c\u800c\u662f\u5206\u522b\u6c42\u503c\u5de6\u53f3\u952e\u8868\u8fbe\u5f0f\uff0c\u518d\u9010\u5217\u6bd4\u8f83\uff08\u53c2\u89c1 MJCompare\uff09\u3002\u89c4\u5212\u5668\u63d0\u4f9b\u8db3\u591f\u7684\u8f93\u5165\u6392\u5e8f\u4fe1\u606f\uff0c\u8ba9\u6267\u884c\u5668\u786e\u5b9a\u6bd4\u8f83\u65b9\u6cd5\u3002\u53ef\u4ee5\u4f7f\u7528\u76f8\u5e94\u7684 B-tree \u6bd4\u8f83\u51fd\u6570\uff0c\u56e0\u4e3a Postgres \u7684\u6392\u5e8f\u8bed\u4e49\u4ec5\u7531 B-tree \u64cd\u4f5c\u7b26\u5bb6\u65cf\u5b9a\u4e49\u3002"]}, {"code": "case T_MergeJoin:\n\t\t\tpname = \"Merge\";\t/* \"Join\" gets added by jointype switch */\n\t\t\tsname = \"Merge Join\";\n\t\t\tbreak;", "title": "\u6838\u5fc3\u6e90\u7801\u4e2d\u7684 EXPLAIN \u6807\u8bc6"}], "strategies": [], "description": ["\u4f7f\u7528\u5f52\u5e76\u6761\u4ef6\u8fde\u63a5\u6709\u5e8f\u8f93\u5165\u6d41\u3002"], "localization": {"status": "complete", "sources": [{"url": "/docs/11/parallel-plans.html", "method": "same-major semantic node", "sha256": "963d71be1a9c27fcc3f5c60b2479c7b94c6d85bfc4e1e20289a1c0e6f284ec85", "language": "zh", "matched_nodes": ["#PARALLEL-PLANS/div[4]/div[2]/ul[0]/li[1]", "#PARALLEL-PLANS/div[4]/p[1]", "#PARALLEL-PLANS/div[5]/p[1]"]}], "language": "zh", "original_text": {"/versions/11/description/0": "Joins ordered input streams using merge clauses.", "/versions/11/facts/0/label": "Core node tag", "/versions/11/facts/1/label": "Structured EXPLAIN Node Type", "/versions/11/facts/2/label": "Inputs", "/versions/11/facts/2/value": "Ordered outer and inner child plans", "/versions/11/facts/3/label": "Output", "/versions/11/facts/3/value": "Joined tuples according to the selected join type", "/versions/11/facts/4/label": "Executor initializer", "/versions/11/facts/5/label": "Memory mechanism", "/versions/11/tables/0/title": "EXPLAIN labels in this source build", "/versions/11/related/1/label": "Using EXPLAIN", "/versions/11/related/2/label": "Parallel plans", "/versions/11/sections/0/title": "EXPLAIN names and attributes", "/versions/11/sections/1/title": "Memory and temporary storage", "/versions/11/sections/2/title": "Parallel execution and instrumentation", "/versions/11/sections/3/title": "Same-version manual discussion", "/versions/11/sections/4/title": "Examples from this manual build", "/versions/11/sections/5/title": "Executor implementation notes", "/versions/11/sections/6/title": "EXPLAIN identity in core source", "/versions/11/memory/description": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/11/sections/0/paragraphs/0": "Structured formats use the Node Type above. Text-format spellings can also include operation, strategy, join type, scan direction or aggregation-stage attributes.", "/versions/11/sections/0/paragraphs/1": "Text names recorded by this source: Merge.", "/versions/11/sections/0/paragraphs/2": "Parallel-aware and parallel-safe are different plan properties. A node running inside a parallel worker is not necessarily a parallel-aware node.", "/versions/11/sections/1/paragraphs/0": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/11/sections/2/paragraphs/0": "The source callbacks below can coordinate execution or collect worker instrumentation. Their presence is not a blanket claim that this node supports a shared parallel scan or shared state.", "/versions/11/sections/2/paragraphs/1": "Callbacks in this build: none extracted from this node implementation.", "/versions/11/sections/3/paragraphs/0": "Merge join requires its input data to be sorted on the join keys. In this plan the tenk1 data is sorted by using an index scan to visit the rows in the correct order, but a sequential scan and sort is preferred for onek , because there are many more rows to be visited in that table. (Sequential-scan-and-sort frequently beats an index scan for sorting many rows, because of the nonsequential disk access required by the index scan.)", "/versions/11/sections/3/paragraphs/1": "Merge joins also have measurement artifacts that can confuse the unwary. A merge join will stop reading one input if it's exhausted the other input and the next key value in the one input is greater than the last key value of the other input; in such a case there can be no more matches and so no need to scan the rest of the first input. This results in not reading all of one child, with results like those mentioned for LIMIT . Also, if the outer (first) child contains rows with duplicate key values, the inner (second) child is backed up and rescanned for the portion of its rows matching that key value. EXPLAIN ANALYZE counts these repeated emissions of the same inner rows as if they were real additional rows. When there are many outer duplicates, the reported actual row count for the inner child plan node can be significantly larger than the number of rows that are actually in the inner relation.", "/versions/11/sections/3/paragraphs/2": "Just as in a non-parallel plan, the driving table may be joined to one or more other tables using a nested loop, hash join, or merge join. The inner side of the join may be any kind of non-parallel plan that is otherwise supported by the planner provided that it is safe to run within a parallel worker. Depending on the join type, the inner side may also be a parallel plan.", "/versions/11/sections/3/paragraphs/3": "In a merge join , the inner side is always a non-parallel plan and therefore executed in full. This may be inefficient, especially if a sort must be performed, because the work and resulting data are duplicated in every cooperating process.", "/versions/11/sections/3/paragraphs/4": "PostgreSQL supports parallel aggregation by aggregating in two stages. First, each process participating in the parallel portion of the query performs an aggregation step, producing a partial result for each group of which that process is aware. This is reflected in the plan as a Partial Aggregate node. Second, the partial results are transferred to the leader via Gather or Gather Merge . Finally, the leader re-aggregates the results across all workers in order to produce the final result. This is reflected in the plan as a Finalize Aggregate node.", "/versions/11/sections/5/paragraphs/0": "Merge-join is done by joining the inner and outer tuples satisfying join clauses of the form ((= outerKey innerKey) ...). The join clause list is provided by the query planner and may contain more than one (= outerKey innerKey) clause (for composite sort key).", "/versions/11/sections/5/paragraphs/1": "However, the query executor needs to know whether an outer tuple is \"greater/smaller\" than an inner tuple so that it can \"synchronize\" the two relations. For example, consider the following relations:", "/versions/11/sections/5/paragraphs/3": "To continue the merge-join, the executor needs to scan both inner and outer relations till the matching tuples 5. It needs to know that currently inner tuple 3 is \"greater\" than outer tuple 1 and therefore it should scan the outer relation first to find a matching tuple and so on.", "/versions/11/sections/5/paragraphs/4": "Therefore, rather than directly executing the merge join clauses, we evaluate the left and right key expressions separately and then compare the columns one at a time (see MJCompare). The planner passes us enough information about the sort ordering of the inputs to allow us to determine how to make the comparison. We may use the appropriate btree comparison function, since Postgres' only notion of ordering is specified by btree opfamilies.", "/versions/11/tables/0/columns/0/label": "Text-format label", "/versions/11/tables/0/columns/1/label": "Structured node identity", "/versions/11/sections/4/blocks/0/paragraphs/0": "Example copied from the PostgreSQL 11.22 manual; it was not executed for this collection.", "/versions/11/sections/4/blocks/0/paragraphs/1": "Another possible type of join is a merge join, illustrated here:", "/versions/11/sections/4/blocks/1/paragraphs/0": "Example copied from the PostgreSQL 11.22 manual; it was not executed for this collection.", "/versions/11/sections/4/blocks/1/paragraphs/1": "One way to look at variant plans is to force the planner to disregard whatever strategy it thought was the cheapest, using the enable/disable flags described in Section 19.7.1 . (This is a crude tool, but useful. See also Section 14.3 .) For example, if we're unconvinced that sequential-scan-and-sort is the best way to deal with table onek in the previous example, we could try"}, "fallback_fields": [], "source_language": "en", "original_snapshot_sha256": "8dfd6e597f914b14ec333c698dcdf470b2129bfa8b349104ff0f2ecaa588aea9"}, "evidence_kind": "source and documentation", "explain_names": ["Merge"], "partial_modes": [], "comparison_data": {"node_tag": "T_MergeJoin", "strategies": [], "text_names": ["Merge"], "initializer": "ExecInitMergeJoin", "partial_modes": [], "memory_mechanism": "unclassified", "parallel_callbacks": []}, "comparison_hash": "b17771ee4d48585afbaba91552e5eb00f05a4b6784aa491387217937a4a30511", "explain_prefixes": ["Parallel"], "runtime_verified": false, "source_inventory": {"explain": "src/backend/commands/explain.c", "executor": "src/backend/executor/execProcnode.c", "implementation": "src/backend/executor/nodeMergejoin.c"}, "parallel_callbacks": []}, "12": {"facts": [{"label": "\u6838\u5fc3\u8282\u70b9\u6807\u7b7e", "value": "T_MergeJoin"}, {"label": "\u7ed3\u6784\u5316 EXPLAIN \u8282\u70b9\u7c7b\u578b", "value": "Merge Join"}, {"label": "\u8f93\u5165", "value": "\u6709\u5e8f\u7684\u5916\u4fa7\u548c\u5185\u4fa7\u5b50\u8ba1\u5212"}, {"label": "\u8f93\u51fa", "value": "\u6309\u6240\u9009\u8fde\u63a5\u7c7b\u578b\u751f\u6210\u7684\u8fde\u63a5\u5143\u7ec4"}, {"label": "\u6267\u884c\u5668\u521d\u59cb\u5316\u51fd\u6570", "value": "ExecInitMergeJoin"}, {"label": "\u5185\u5b58\u673a\u5236", "value": "unclassified"}], "memory": {"evidence": [{"url": "https://ftp.postgresql.org/pub/source/v12.22/postgresql-12.22.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "f849259598dabde3817453142090df89d7286452a516d4a45e22597a7cd450ca", "archive_sha256": "8df3c0474782589d3c6f374b5133b1bd14d168086edbc13c6e72e67dd4527a3b"}], "mechanism": "unclassified", "description": "\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002", "source_notes": []}, "tables": [{"key": "explain-labels", "rows": [{"label": "Merge", "identity": "Merge Join"}], "title": "\u672c\u6784\u5efa\u4e2d\u7684 EXPLAIN \u6807\u7b7e", "columns": [{"key": "label", "label": "\u6587\u672c\u683c\u5f0f\u6807\u7b7e"}, {"key": "identity", "label": "\u7ed3\u6784\u5316\u8282\u70b9\u6807\u8bc6"}]}], "related": [{"url": "/wiki/sql/explain/?v=12", "label": "EXPLAIN"}, {"url": "/docs/12/using-explain.html", "label": "\u4f7f\u7528 EXPLAIN"}, {"url": "/docs/12/parallel-plans.html", "label": "\u5e76\u884c\u8ba1\u5212"}, {"url": "/wiki/guc/enable_mergejoin/?v=12", "label": "enable_mergejoin"}], "release": {"ref": "PostgreSQL 12.22 source archive", "label": "12.22", "major": "12", "channel": "historical", "revision": "8df3c0474782589d3c6f374b5133b1bd14d168086edbc13c6e72e67dd4527a3b", "source_url": "https://ftp.postgresql.org/pub/source/v12.22/postgresql-12.22.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "https://ftp.postgresql.org/pub/source/v12.22/postgresql-12.22.tar.bz2", "line": 1120, "path": "src/backend/commands/explain.c", "label": "src/backend/commands/explain.c:1120", "sha256": "d02ea84fdaa201de5d9360645a9f24bfbd2c31f7d45a639e09560ac0e6b6471d", "archive_sha256": "8df3c0474782589d3c6f374b5133b1bd14d168086edbc13c6e72e67dd4527a3b"}, {"url": "https://ftp.postgresql.org/pub/source/v12.22/postgresql-12.22.tar.bz2", "line": 295, "path": "src/backend/executor/execProcnode.c", "label": "src/backend/executor/execProcnode.c:295", "sha256": "311b17379fe54e3f342fe5ad41c43afbdfa1b844978db2bb2eb22b82520d3256", "archive_sha256": "8df3c0474782589d3c6f374b5133b1bd14d168086edbc13c6e72e67dd4527a3b"}, {"url": "https://ftp.postgresql.org/pub/source/v12.22/postgresql-12.22.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "f849259598dabde3817453142090df89d7286452a516d4a45e22597a7cd450ca", "archive_sha256": "8df3c0474782589d3c6f374b5133b1bd14d168086edbc13c6e72e67dd4527a3b"}, {"url": "https://ftp.postgresql.org/pub/source/v12.22/postgresql-12.22.tar.bz2", "path": "src/include/nodes/plannodes.h", "label": "src/include/nodes/plannodes.h", "sha256": "b0c4a0aeb48660ce06e5e700d5529ca9066fd16682bd15783d6e71b5420b07b0", "archive_sha256": "8df3c0474782589d3c6f374b5133b1bd14d168086edbc13c6e72e67dd4527a3b"}, {"url": "https://pg.center/docs/12/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 12.22 \u00b7 using-explain", "sha256": "06297525f2180b07e752837a3351be9c871b56559f535bcd0a67dec9baac10c0", "language": "en", "original_url": "/docs/12/using-explain.html#USING-EXPLAIN-BASICS"}, {"url": "https://pg.center/docs/12/using-explain.html#USING-EXPLAIN-CAVEATS", "path": "using-explain.html", "label": "PostgreSQL 12.22 \u00b7 using-explain", "sha256": "06297525f2180b07e752837a3351be9c871b56559f535bcd0a67dec9baac10c0", "language": "en", "original_url": "/docs/12/using-explain.html#USING-EXPLAIN-CAVEATS"}, {"url": "https://pg.center/docs/12/parallel-plans.html#PARALLEL-JOINS", "path": "parallel-plans.html", "label": "PostgreSQL 12.22 \u00b7 parallel-plans", "sha256": "fa33380814ee65998f524524f8681d70cf3b1198d54b39847b00462b01517ffb", "language": "en", "original_url": "/docs/12/parallel-plans.html#PARALLEL-JOINS"}, {"url": "https://pg.center/docs/12/parallel-plans.html#PARALLEL-AGGREGATION", "path": "parallel-plans.html", "label": "PostgreSQL 12.22 \u00b7 parallel-plans", "sha256": "fa33380814ee65998f524524f8681d70cf3b1198d54b39847b00462b01517ffb", "language": "en", "original_url": "/docs/12/parallel-plans.html#PARALLEL-AGGREGATION"}], "node_tag": "T_MergeJoin", "sections": [{"title": "EXPLAIN \u540d\u79f0\u4e0e\u5c5e\u6027", "paragraphs": ["\u7ed3\u6784\u5316\u683c\u5f0f\u4f7f\u7528\u4e0a\u8ff0 Node Type\u3002\u6587\u672c\u683c\u5f0f\u540d\u79f0\u8fd8\u53ef\u80fd\u5305\u542b\u64cd\u4f5c\u3001\u7b56\u7565\u3001\u8fde\u63a5\u7c7b\u578b\u3001\u626b\u63cf\u65b9\u5411\u6216\u805a\u5408\u9636\u6bb5\u5c5e\u6027\u3002", "\u6b64\u6e90\u7801\u8bb0\u5f55\u7684\u6587\u672c\u540d\u79f0\uff1aMerge.", "\u5e76\u884c\u611f\u77e5\u4e0e\u5e76\u884c\u5b89\u5168\u662f\u4e0d\u540c\u7684\u8ba1\u5212\u5c5e\u6027\u3002\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u5185\u8fd0\u884c\u7684\u8282\u70b9\u4e0d\u4e00\u5b9a\u662f\u5e76\u884c\u611f\u77e5\u8282\u70b9\u3002"]}, {"title": "\u5185\u5b58\u4e0e\u4e34\u65f6\u5b58\u50a8", "paragraphs": ["\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002"]}, {"title": "\u5e76\u884c\u6267\u884c\u4e0e\u8fd0\u884c\u4fe1\u606f\u91c7\u96c6", "paragraphs": ["\u4ee5\u4e0b\u6e90\u7801\u56de\u8c03\u53ef\u4ee5\u534f\u8c03\u6267\u884c\u6216\u6536\u96c6\u5de5\u4f5c\u8fdb\u7a0b\u7684\u6d4b\u91cf\u6570\u636e\u3002\u56de\u8c03\u5b58\u5728\u4e0d\u4ee3\u8868\u8be5\u8282\u70b9\u666e\u904d\u652f\u6301\u5171\u4eab\u5e76\u884c\u626b\u63cf\u6216\u5171\u4eab\u72b6\u6001\u3002", "\u6b64\u6784\u5efa\u7684\u56de\u8c03\uff1anone extracted from this node implementation."]}, {"title": "\u540c\u7248\u672c\u624b\u518c\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u8981\u6c42\u8f93\u5165\u6309\u8fde\u63a5\u952e\u6392\u5e8f\u3002\u6b64\u8ba1\u5212\u901a\u8fc7\u7d22\u5f15\u626b\u63cf\u6309\u987a\u5e8f\u8bfb\u53d6 tenk1\uff1b\u5bf9\u4e8e onek\uff0c\u5219\u503e\u5411\u4e8e\u987a\u5e8f\u626b\u63cf\u540e\u6392\u5e8f\uff0c\u56e0\u4e3a\u8be5\u8868\u8981\u8bbf\u95ee\u7684\u884c\u66f4\u591a\u3002\uff08\u5bf9\u5927\u91cf\u884c\u6392\u5e8f\u65f6\uff0c\u987a\u5e8f\u626b\u63cf\u52a0\u6392\u5e8f\u5e38\u5e38\u4f18\u4e8e\u7d22\u5f15\u626b\u63cf\uff0c\u56e0\u4e3a\u540e\u8005\u9700\u8981\u975e\u987a\u5e8f\u78c1\u76d8\u8bbf\u95ee\u3002\uff09", "\u5f52\u5e76\u8fde\u63a5\u7684\u6d4b\u91cf\u7ed3\u679c\u4e5f\u53ef\u80fd\u4ea7\u751f\u8bef\u5bfc\u3002\u82e5\u4e00\u4fa7\u8f93\u5165\u5df2\u8017\u5c3d\uff0c\u53e6\u4e00\u4fa7\u7684\u4e0b\u4e00\u4e2a\u952e\u503c\u53c8\u5927\u4e8e\u5df2\u8017\u5c3d\u8f93\u5165\u7684\u6700\u540e\u4e00\u4e2a\u952e\u503c\uff0c\u5c31\u4e0d\u4f1a\u518d\u6709\u5339\u914d\uff0c\u56e0\u6b64\u4f1a\u505c\u6b62\u8bfb\u53d6\u53e6\u4e00\u4fa7\u3002\u8fd9\u6837\u4fbf\u672a\u8bfb\u53d6\u8be5\u5b50\u8282\u70b9\u7684\u5168\u90e8\u884c\uff0c\u7c7b\u4f3c LIMIT \u7684\u60c5\u51b5\u3002\u53e6\u5916\uff0c\u5916\u4fa7\uff08\u7b2c\u4e00\u4e2a\uff09\u5b50\u8282\u70b9\u6709\u91cd\u590d\u952e\u503c\u65f6\uff0c\u5185\u4fa7\uff08\u7b2c\u4e8c\u4e2a\uff09\u5b50\u8282\u70b9\u4f1a\u56de\u9000\u5e76\u91cd\u65b0\u626b\u63cf\u5339\u914d\u8be5\u952e\u503c\u7684\u884c\u3002EXPLAIN ANALYZE \u4f1a\u5c06\u5185\u4fa7\u91cd\u590d\u8f93\u51fa\u7684\u884c\u8ba1\u4f5c\u989d\u5916\u7684\u771f\u5b9e\u884c\u3002\u56e0\u6b64\u5916\u4fa7\u91cd\u590d\u503c\u5f88\u591a\u65f6\uff0c\u5185\u4fa7\u8ba1\u5212\u8282\u70b9\u62a5\u544a\u7684\u5b9e\u9645\u884c\u6570\u53ef\u80fd\u663e\u8457\u8d85\u8fc7\u5185\u4fa7\u5173\u7cfb\u4e2d\u7684\u5b9e\u9645\u884c\u6570\u3002", "\u4e0e\u975e\u5e76\u884c\u8ba1\u5212\u4e00\u6837\uff0c\u9a71\u52a8\u8868\u53ef\u4ee5\u901a\u8fc7\u5d4c\u5957\u5faa\u73af\u3001\u54c8\u5e0c\u8fde\u63a5\u6216\u5f52\u5e76\u8fde\u63a5\u4e0e\u4e00\u4e2a\u6216\u591a\u4e2a\u5176\u4ed6\u8868\u8fde\u63a5\u3002\u8fde\u63a5\u7684\u5185\u4fa7\u53ef\u4ee5\u662f\u89c4\u5212\u5668\u652f\u6301\u7684\u4efb\u4f55\u7c7b\u578b\u7684\u975e\u5e76\u884c\u8ba1\u5212\uff0c\u53ea\u8981\u5b83\u80fd\u591f\u5b89\u5168\u5730\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u4e2d\u8fd0\u884c\u3002\u6839\u636e\u8fde\u63a5\u7c7b\u578b\uff0c\u5185\u4fa7\u4e5f\u53ef\u4ee5\u662f\u5e76\u884c\u8ba1\u5212\u3002", "\u5728 \u5f52\u5e76\u8fde\u63a5 \u4e2d\uff0c\u5185\u4fa7\u59cb\u7ec8\u662f\u975e\u5e76\u884c\u8ba1\u5212\uff0c\u56e0\u6b64\u4f1a\u88ab\u5b8c\u6574\u6267\u884c\u3002\u8fd9\u53ef\u80fd\u6548\u7387\u4e0d\u9ad8\uff0c\u5c24\u5176\u662f\u5728\u5fc5\u987b\u6267\u884c\u6392\u5e8f\u65f6\uff0c\u56e0\u4e3a\u5de5\u4f5c\u91cf\u548c\u7ed3\u679c\u6570\u636e\u4f1a\u5728\u6bcf\u4e2a\u534f\u4f5c\u8fdb\u7a0b\u4e2d\u91cd\u590d\u3002", "PostgreSQL \u901a\u8fc7\u5206\u4e24\u4e2a\u9636\u6bb5\u8fdb\u884c\u805a\u5408\u6765\u652f\u6301\u5e76\u884c\u805a\u5408\u3002\u9996\u5148\uff0c\u6bcf\u4e2a\u53c2\u4e0e\u67e5\u8be2\u5e76\u884c\u90e8\u5206\u7684\u8fdb\u7a0b\u6267\u884c\u4e00\u4e2a\u805a\u5408\u6b65\u9aa4\uff0c\u4e3a\u8be5\u8fdb\u7a0b\u6240\u89c1\u5230\u7684\u6bcf\u4e2a\u5206\u7ec4\u4ea7\u751f\u4e00\u4e2a\u90e8\u5206\u7ed3\u679c\u3002\u8fd9\u5728\u8ba1\u5212\u4e2d\u4f53\u73b0\u4e3a\u4e00\u4e2a Partial Aggregate \u8282\u70b9\u3002\u7136\u540e\uff0c\u90e8\u5206\u7ed3\u679c\u901a\u8fc7 Gather \u6216 Gather Merge \u4f20\u9001\u7ed9\u9886\u5bfc\u8005\u3002\u6700\u540e\uff0c\u9886\u5bfc\u8005\u4f1a\u628a\u6765\u81ea\u6240\u6709\u5de5\u4f5c\u8fdb\u7a0b\u7684\u7ed3\u679c\u518d\u6b21\u805a\u5408\uff0c\u4ee5\u4ea7\u751f\u6700\u7ec8\u7ed3\u679c\u3002\u8fd9\u5728\u8ba1\u5212\u4e2d\u4f53\u73b0\u4e3a\u4e00\u4e2a Finalize Aggregate \u8282\u70b9\u3002"]}, {"title": "\u672c\u7248\u624b\u518c\u4e2d\u7684\u793a\u4f8b", "blocks": [{"code": "EXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=198.11..268.19 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..656.28 rows=101 width=244)\n         Filter: (unique1 < 100)\n   ->  Sort  (cost=197.83..200.33 rows=1000 width=244)\n         Sort Key: t2.unique2\n         ->  Seq Scan on onek t2  (cost=0.00..148.00 rows=1000 width=244)", "source": {"url": "/docs/12/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 12.22 \u00b7 using-explain", "sha256": "06297525f2180b07e752837a3351be9c871b56559f535bcd0a67dec9baac10c0"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 12.22 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u53e6\u4e00\u79cd\u53ef\u80fd\u7684\u8fde\u63a5\u65b9\u5f0f\u662f\u5f52\u5e76\u8fde\u63a5\uff0c\u5982\u4e0b\u6240\u793a\uff1a"]}, {"code": "SET enable_sort = off;\n\nEXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=0.56..292.65 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..656.28 rows=101 width=244)\n         Filter: (unique1 < 100)\n   ->  Index Scan using onek_unique2 on onek t2  (cost=0.28..224.79 rows=1000 width=244)", "source": {"url": "/docs/12/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 12.22 \u00b7 using-explain", "sha256": "06297525f2180b07e752837a3351be9c871b56559f535bcd0a67dec9baac10c0"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 12.22 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u89c2\u5bdf\u5907\u9009\u8ba1\u5212\u7684\u4e00\u79cd\u529e\u6cd5\uff0c\u662f\u4f7f\u7528\u7b2c 19.7.1 \u8282\u7684\u542f\u7528\uff0f\u7981\u7528\u6807\u5fd7\uff0c\u5f3a\u5236\u89c4\u5212\u5668\u5ffd\u7565\u5b83\u8ba4\u4e3a\u4ee3\u4ef7\u6700\u4f4e\u7684\u7b56\u7565\u3002\u8fd9\u79cd\u5de5\u5177\u8f83\u4e3a\u7c97\u7565\uff0c\u4f46\u5f88\u6709\u7528\uff0c\u53e6\u89c1\u7b2c 14.3 \u8282\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4e0d\u786e\u5b9a\u524d\u4f8b\u4e2d\u5bf9 onek \u8868\u91c7\u7528\u987a\u5e8f\u626b\u63cf\u518d\u6392\u5e8f\u662f\u5426\u6700\u4f73\uff0c\u53ef\u4ee5\u5c1d\u8bd5\uff1a"]}]}, {"title": "\u6267\u884c\u5668\u5b9e\u73b0\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u5bf9\u6ee1\u8db3 ((= outerKey innerKey) ...) \u5f62\u5f0f\u8fde\u63a5\u6761\u4ef6\u7684\u5185\u5916\u4fa7\u5143\u7ec4\u6267\u884c\u8fde\u63a5\u3002\u8fde\u63a5\u6761\u4ef6\u5217\u8868\u7531\u67e5\u8be2\u89c4\u5212\u5668\u63d0\u4f9b\uff0c\u53ef\u4ee5\u5305\u542b\u591a\u4e2a (= outerKey innerKey) \u6761\u4ef6\uff0c\u4ee5\u652f\u6301\u590d\u5408\u6392\u5e8f\u952e\u3002", "\u4e0d\u8fc7\uff0c\u67e5\u8be2\u6267\u884c\u5668\u9700\u8981\u5224\u65ad\u5916\u4fa7\u5143\u7ec4\u662f\u5426\u201c\u5927\u4e8e\uff0f\u5c0f\u4e8e\u201d\u5185\u4fa7\u5143\u7ec4\uff0c\u4ee5\u4fbf\u201c\u540c\u6b65\u201d\u4e24\u4e2a\u5173\u7cfb\u3002\u4f8b\u5982\uff0c\u8003\u8651\u4ee5\u4e0b\u5173\u7cfb\uff1a", "outer: (0 ^1 1 2 5 5 5 6 6 7) current tuple: 1 inner: (1 ^3 5 5 5 5 6) current tuple: 3", "\u4e3a\u7ee7\u7eed\u5f52\u5e76\u8fde\u63a5\uff0c\u6267\u884c\u5668\u9700\u8981\u626b\u63cf\u5185\u5916\u4fa7\u5173\u7cfb\uff0c\u76f4\u5230\u627e\u5230\u5339\u914d\u7684\u5143\u7ec4 5\u3002\u5b83\u9700\u8981\u77e5\u9053\u5f53\u524d\u5185\u4fa7\u5143\u7ec4 3\u201c\u5927\u4e8e\u201d\u5916\u4fa7\u5143\u7ec4 1\uff0c\u56e0\u6b64\u5e94\u5148\u626b\u63cf\u5916\u4fa7\u5173\u7cfb\u4ee5\u5bfb\u627e\u5339\u914d\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002", "\u56e0\u6b64\uff0c\u4e0d\u76f4\u63a5\u6267\u884c\u5f52\u5e76\u8fde\u63a5\u6761\u4ef6\uff0c\u800c\u662f\u5206\u522b\u6c42\u503c\u5de6\u53f3\u952e\u8868\u8fbe\u5f0f\uff0c\u518d\u9010\u5217\u6bd4\u8f83\uff08\u53c2\u89c1 MJCompare\uff09\u3002\u89c4\u5212\u5668\u63d0\u4f9b\u8db3\u591f\u7684\u8f93\u5165\u6392\u5e8f\u4fe1\u606f\uff0c\u8ba9\u6267\u884c\u5668\u786e\u5b9a\u6bd4\u8f83\u65b9\u6cd5\u3002\u53ef\u4ee5\u4f7f\u7528\u76f8\u5e94\u7684 B-tree \u6bd4\u8f83\u51fd\u6570\uff0c\u56e0\u4e3a Postgres \u7684\u6392\u5e8f\u8bed\u4e49\u4ec5\u7531 B-tree \u64cd\u4f5c\u7b26\u5bb6\u65cf\u5b9a\u4e49\u3002"]}, {"code": "case T_MergeJoin:\n\t\t\tpname = \"Merge\";\t/* \"Join\" gets added by jointype switch */\n\t\t\tsname = \"Merge Join\";\n\t\t\tbreak;", "title": "\u6838\u5fc3\u6e90\u7801\u4e2d\u7684 EXPLAIN \u6807\u8bc6"}], "strategies": [], "description": ["\u4f7f\u7528\u5f52\u5e76\u6761\u4ef6\u8fde\u63a5\u6709\u5e8f\u8f93\u5165\u6d41\u3002"], "localization": {"status": "complete", "sources": [{"url": "/docs/12/parallel-plans.html", "method": "same-major semantic node", "sha256": "4aaca92475f243dcddffd80d9af558330f8f3b0ac3cbe8872b0d2901e14fe684", "language": "zh", "matched_nodes": ["#PARALLEL-PLANS/div[4]/div[2]/ul[0]/li[1]", "#PARALLEL-PLANS/div[4]/p[1]", "#PARALLEL-PLANS/div[5]/p[1]"]}], "language": "zh", "original_text": {"/versions/12/description/0": "Joins ordered input streams using merge clauses.", "/versions/12/facts/0/label": "Core node tag", "/versions/12/facts/1/label": "Structured EXPLAIN Node Type", "/versions/12/facts/2/label": "Inputs", "/versions/12/facts/2/value": "Ordered outer and inner child plans", "/versions/12/facts/3/label": "Output", "/versions/12/facts/3/value": "Joined tuples according to the selected join type", "/versions/12/facts/4/label": "Executor initializer", "/versions/12/facts/5/label": "Memory mechanism", "/versions/12/tables/0/title": "EXPLAIN labels in this source build", "/versions/12/related/1/label": "Using EXPLAIN", "/versions/12/related/2/label": "Parallel plans", "/versions/12/sections/0/title": "EXPLAIN names and attributes", "/versions/12/sections/1/title": "Memory and temporary storage", "/versions/12/sections/2/title": "Parallel execution and instrumentation", "/versions/12/sections/3/title": "Same-version manual discussion", "/versions/12/sections/4/title": "Examples from this manual build", "/versions/12/sections/5/title": "Executor implementation notes", "/versions/12/sections/6/title": "EXPLAIN identity in core source", "/versions/12/memory/description": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/12/sections/0/paragraphs/0": "Structured formats use the Node Type above. Text-format spellings can also include operation, strategy, join type, scan direction or aggregation-stage attributes.", "/versions/12/sections/0/paragraphs/1": "Text names recorded by this source: Merge.", "/versions/12/sections/0/paragraphs/2": "Parallel-aware and parallel-safe are different plan properties. A node running inside a parallel worker is not necessarily a parallel-aware node.", "/versions/12/sections/1/paragraphs/0": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/12/sections/2/paragraphs/0": "The source callbacks below can coordinate execution or collect worker instrumentation. Their presence is not a blanket claim that this node supports a shared parallel scan or shared state.", "/versions/12/sections/2/paragraphs/1": "Callbacks in this build: none extracted from this node implementation.", "/versions/12/sections/3/paragraphs/0": "Merge join requires its input data to be sorted on the join keys. In this plan the tenk1 data is sorted by using an index scan to visit the rows in the correct order, but a sequential scan and sort is preferred for onek , because there are many more rows to be visited in that table. (Sequential-scan-and-sort frequently beats an index scan for sorting many rows, because of the nonsequential disk access required by the index scan.)", "/versions/12/sections/3/paragraphs/1": "Merge joins also have measurement artifacts that can confuse the unwary. A merge join will stop reading one input if it's exhausted the other input and the next key value in the one input is greater than the last key value of the other input; in such a case there can be no more matches and so no need to scan the rest of the first input. This results in not reading all of one child, with results like those mentioned for LIMIT . Also, if the outer (first) child contains rows with duplicate key values, the inner (second) child is backed up and rescanned for the portion of its rows matching that key value. EXPLAIN ANALYZE counts these repeated emissions of the same inner rows as if they were real additional rows. When there are many outer duplicates, the reported actual row count for the inner child plan node can be significantly larger than the number of rows that are actually in the inner relation.", "/versions/12/sections/3/paragraphs/2": "Just as in a non-parallel plan, the driving table may be joined to one or more other tables using a nested loop, hash join, or merge join. The inner side of the join may be any kind of non-parallel plan that is otherwise supported by the planner provided that it is safe to run within a parallel worker. Depending on the join type, the inner side may also be a parallel plan.", "/versions/12/sections/3/paragraphs/3": "In a merge join , the inner side is always a non-parallel plan and therefore executed in full. This may be inefficient, especially if a sort must be performed, because the work and resulting data are duplicated in every cooperating process.", "/versions/12/sections/3/paragraphs/4": "PostgreSQL supports parallel aggregation by aggregating in two stages. First, each process participating in the parallel portion of the query performs an aggregation step, producing a partial result for each group of which that process is aware. This is reflected in the plan as a Partial Aggregate node. Second, the partial results are transferred to the leader via Gather or Gather Merge . Finally, the leader re-aggregates the results across all workers in order to produce the final result. This is reflected in the plan as a Finalize Aggregate node.", "/versions/12/sections/5/paragraphs/0": "Merge-join is done by joining the inner and outer tuples satisfying join clauses of the form ((= outerKey innerKey) ...). The join clause list is provided by the query planner and may contain more than one (= outerKey innerKey) clause (for composite sort key).", "/versions/12/sections/5/paragraphs/1": "However, the query executor needs to know whether an outer tuple is \"greater/smaller\" than an inner tuple so that it can \"synchronize\" the two relations. For example, consider the following relations:", "/versions/12/sections/5/paragraphs/3": "To continue the merge-join, the executor needs to scan both inner and outer relations till the matching tuples 5. It needs to know that currently inner tuple 3 is \"greater\" than outer tuple 1 and therefore it should scan the outer relation first to find a matching tuple and so on.", "/versions/12/sections/5/paragraphs/4": "Therefore, rather than directly executing the merge join clauses, we evaluate the left and right key expressions separately and then compare the columns one at a time (see MJCompare). The planner passes us enough information about the sort ordering of the inputs to allow us to determine how to make the comparison. We may use the appropriate btree comparison function, since Postgres' only notion of ordering is specified by btree opfamilies.", "/versions/12/tables/0/columns/0/label": "Text-format label", "/versions/12/tables/0/columns/1/label": "Structured node identity", "/versions/12/sections/4/blocks/0/paragraphs/0": "Example copied from the PostgreSQL 12.22 manual; it was not executed for this collection.", "/versions/12/sections/4/blocks/0/paragraphs/1": "Another possible type of join is a merge join, illustrated here:", "/versions/12/sections/4/blocks/1/paragraphs/0": "Example copied from the PostgreSQL 12.22 manual; it was not executed for this collection.", "/versions/12/sections/4/blocks/1/paragraphs/1": "One way to look at variant plans is to force the planner to disregard whatever strategy it thought was the cheapest, using the enable/disable flags described in Section 19.7.1 . (This is a crude tool, but useful. See also Section 14.3 .) For example, if we're unconvinced that sequential-scan-and-sort is the best way to deal with table onek in the previous example, we could try"}, "fallback_fields": [], "source_language": "en", "original_snapshot_sha256": "81404c6d4cd6b00b8106de5f35898f98aa9f9fd2e744f27f7b5f31c1be17a18d"}, "evidence_kind": "source and documentation", "explain_names": ["Merge"], "partial_modes": [], "comparison_data": {"node_tag": "T_MergeJoin", "strategies": [], "text_names": ["Merge"], "initializer": "ExecInitMergeJoin", "partial_modes": [], "memory_mechanism": "unclassified", "parallel_callbacks": []}, "comparison_hash": "b17771ee4d48585afbaba91552e5eb00f05a4b6784aa491387217937a4a30511", "explain_prefixes": ["Parallel"], "runtime_verified": false, "source_inventory": {"explain": "src/backend/commands/explain.c", "executor": "src/backend/executor/execProcnode.c", "implementation": "src/backend/executor/nodeMergejoin.c"}, "parallel_callbacks": []}, "13": {"facts": [{"label": "\u6838\u5fc3\u8282\u70b9\u6807\u7b7e", "value": "T_MergeJoin"}, {"label": "\u7ed3\u6784\u5316 EXPLAIN \u8282\u70b9\u7c7b\u578b", "value": "Merge Join"}, {"label": "\u8f93\u5165", "value": "\u6709\u5e8f\u7684\u5916\u4fa7\u548c\u5185\u4fa7\u5b50\u8ba1\u5212"}, {"label": "\u8f93\u51fa", "value": "\u6309\u6240\u9009\u8fde\u63a5\u7c7b\u578b\u751f\u6210\u7684\u8fde\u63a5\u5143\u7ec4"}, {"label": "\u6267\u884c\u5668\u521d\u59cb\u5316\u51fd\u6570", "value": "ExecInitMergeJoin"}, {"label": "\u5185\u5b58\u673a\u5236", "value": "unclassified"}], "memory": {"evidence": [{"url": "https://ftp.postgresql.org/pub/source/v13.23/postgresql-13.23.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "18848e4bb13e8b2c3eb54cdb75a9e9bbb2f058051e1ad9476873d4c60a0f1a7f", "archive_sha256": "6ec3c82726af92b7dec873fa1cdf881eca92a4219787dfad05acb6b10e041fd6"}], "mechanism": "unclassified", "description": "\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002", "source_notes": []}, "tables": [{"key": "explain-labels", "rows": [{"label": "Merge", "identity": "Merge Join"}], "title": "\u672c\u6784\u5efa\u4e2d\u7684 EXPLAIN \u6807\u7b7e", "columns": [{"key": "label", "label": "\u6587\u672c\u683c\u5f0f\u6807\u7b7e"}, {"key": "identity", "label": "\u7ed3\u6784\u5316\u8282\u70b9\u6807\u8bc6"}]}], "related": [{"url": "/wiki/sql/explain/?v=13", "label": "EXPLAIN"}, {"url": "/docs/13/using-explain.html", "label": "\u4f7f\u7528 EXPLAIN"}, {"url": "/docs/13/parallel-plans.html", "label": "\u5e76\u884c\u8ba1\u5212"}, {"url": "/wiki/guc/enable_mergejoin/?v=13", "label": "enable_mergejoin"}], "release": {"ref": "PostgreSQL 13.23 source archive", "label": "13.23", "major": "13", "channel": "historical", "revision": "6ec3c82726af92b7dec873fa1cdf881eca92a4219787dfad05acb6b10e041fd6", "source_url": "https://ftp.postgresql.org/pub/source/v13.23/postgresql-13.23.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "https://ftp.postgresql.org/pub/source/v13.23/postgresql-13.23.tar.bz2", "line": 1178, "path": "src/backend/commands/explain.c", "label": "src/backend/commands/explain.c:1178", "sha256": "541713e0e7f1c9cc352c2b6028964d440c19d2678a4463000094c24a88c1e730", "archive_sha256": "6ec3c82726af92b7dec873fa1cdf881eca92a4219787dfad05acb6b10e041fd6"}, {"url": "https://ftp.postgresql.org/pub/source/v13.23/postgresql-13.23.tar.bz2", "line": 295, "path": "src/backend/executor/execProcnode.c", "label": "src/backend/executor/execProcnode.c:295", "sha256": "d085ee99acfa00587e6ade3a1d9f8108a0566beedbbee3f54a50c9fc0cc2e875", "archive_sha256": "6ec3c82726af92b7dec873fa1cdf881eca92a4219787dfad05acb6b10e041fd6"}, {"url": "https://ftp.postgresql.org/pub/source/v13.23/postgresql-13.23.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "18848e4bb13e8b2c3eb54cdb75a9e9bbb2f058051e1ad9476873d4c60a0f1a7f", "archive_sha256": "6ec3c82726af92b7dec873fa1cdf881eca92a4219787dfad05acb6b10e041fd6"}, {"url": "https://ftp.postgresql.org/pub/source/v13.23/postgresql-13.23.tar.bz2", "path": "src/include/nodes/plannodes.h", "label": "src/include/nodes/plannodes.h", "sha256": "dcb296833777b02008c4b6bae8e8f7c6423b7ffba21f36702597c9d596d039ab", "archive_sha256": "6ec3c82726af92b7dec873fa1cdf881eca92a4219787dfad05acb6b10e041fd6"}, {"url": "https://pg.center/docs/13/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 13.23 \u00b7 using-explain", "sha256": "650fd8629382d5dc8f9f8412c50ec5f32442a9ad2f98ca88e5348a7c2bd0ac7a", "language": "en", "original_url": "/docs/13/using-explain.html#USING-EXPLAIN-BASICS"}, {"url": "https://pg.center/docs/13/using-explain.html#USING-EXPLAIN-CAVEATS", "path": "using-explain.html", "label": "PostgreSQL 13.23 \u00b7 using-explain", "sha256": "650fd8629382d5dc8f9f8412c50ec5f32442a9ad2f98ca88e5348a7c2bd0ac7a", "language": "en", "original_url": "/docs/13/using-explain.html#USING-EXPLAIN-CAVEATS"}, {"url": "https://pg.center/docs/13/parallel-plans.html#PARALLEL-JOINS", "path": "parallel-plans.html", "label": "PostgreSQL 13.23 \u00b7 parallel-plans", "sha256": "025ad8564a8461b676c9153f9e084429cca0ef86c968090689b082120060f3d0", "language": "en", "original_url": "/docs/13/parallel-plans.html#PARALLEL-JOINS"}, {"url": "https://pg.center/docs/13/parallel-plans.html#PARALLEL-AGGREGATION", "path": "parallel-plans.html", "label": "PostgreSQL 13.23 \u00b7 parallel-plans", "sha256": "025ad8564a8461b676c9153f9e084429cca0ef86c968090689b082120060f3d0", "language": "en", "original_url": "/docs/13/parallel-plans.html#PARALLEL-AGGREGATION"}], "node_tag": "T_MergeJoin", "sections": [{"title": "EXPLAIN \u540d\u79f0\u4e0e\u5c5e\u6027", "paragraphs": ["\u7ed3\u6784\u5316\u683c\u5f0f\u4f7f\u7528\u4e0a\u8ff0 Node Type\u3002\u6587\u672c\u683c\u5f0f\u540d\u79f0\u8fd8\u53ef\u80fd\u5305\u542b\u64cd\u4f5c\u3001\u7b56\u7565\u3001\u8fde\u63a5\u7c7b\u578b\u3001\u626b\u63cf\u65b9\u5411\u6216\u805a\u5408\u9636\u6bb5\u5c5e\u6027\u3002", "\u6b64\u6e90\u7801\u8bb0\u5f55\u7684\u6587\u672c\u540d\u79f0\uff1aMerge.", "\u5e76\u884c\u611f\u77e5\u4e0e\u5e76\u884c\u5b89\u5168\u662f\u4e0d\u540c\u7684\u8ba1\u5212\u5c5e\u6027\u3002\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u5185\u8fd0\u884c\u7684\u8282\u70b9\u4e0d\u4e00\u5b9a\u662f\u5e76\u884c\u611f\u77e5\u8282\u70b9\u3002"]}, {"title": "\u5185\u5b58\u4e0e\u4e34\u65f6\u5b58\u50a8", "paragraphs": ["\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002"]}, {"title": "\u5e76\u884c\u6267\u884c\u4e0e\u8fd0\u884c\u4fe1\u606f\u91c7\u96c6", "paragraphs": ["\u4ee5\u4e0b\u6e90\u7801\u56de\u8c03\u53ef\u4ee5\u534f\u8c03\u6267\u884c\u6216\u6536\u96c6\u5de5\u4f5c\u8fdb\u7a0b\u7684\u6d4b\u91cf\u6570\u636e\u3002\u56de\u8c03\u5b58\u5728\u4e0d\u4ee3\u8868\u8be5\u8282\u70b9\u666e\u904d\u652f\u6301\u5171\u4eab\u5e76\u884c\u626b\u63cf\u6216\u5171\u4eab\u72b6\u6001\u3002", "\u6b64\u6784\u5efa\u7684\u56de\u8c03\uff1anone extracted from this node implementation."]}, {"title": "\u540c\u7248\u672c\u624b\u518c\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u8981\u6c42\u8f93\u5165\u6309\u8fde\u63a5\u952e\u6392\u5e8f\u3002\u6b64\u8ba1\u5212\u901a\u8fc7\u7d22\u5f15\u626b\u63cf\u6309\u987a\u5e8f\u8bfb\u53d6 tenk1\uff1b\u5bf9\u4e8e onek\uff0c\u5219\u503e\u5411\u4e8e\u987a\u5e8f\u626b\u63cf\u540e\u6392\u5e8f\uff0c\u56e0\u4e3a\u8be5\u8868\u8981\u8bbf\u95ee\u7684\u884c\u66f4\u591a\u3002\uff08\u5bf9\u5927\u91cf\u884c\u6392\u5e8f\u65f6\uff0c\u987a\u5e8f\u626b\u63cf\u52a0\u6392\u5e8f\u5e38\u5e38\u4f18\u4e8e\u7d22\u5f15\u626b\u63cf\uff0c\u56e0\u4e3a\u540e\u8005\u9700\u8981\u975e\u987a\u5e8f\u78c1\u76d8\u8bbf\u95ee\u3002\uff09", "\u5f52\u5e76\u8fde\u63a5\u7684\u6d4b\u91cf\u7ed3\u679c\u4e5f\u53ef\u80fd\u4ea7\u751f\u8bef\u5bfc\u3002\u82e5\u4e00\u4fa7\u8f93\u5165\u5df2\u8017\u5c3d\uff0c\u53e6\u4e00\u4fa7\u7684\u4e0b\u4e00\u4e2a\u952e\u503c\u53c8\u5927\u4e8e\u5df2\u8017\u5c3d\u8f93\u5165\u7684\u6700\u540e\u4e00\u4e2a\u952e\u503c\uff0c\u5c31\u4e0d\u4f1a\u518d\u6709\u5339\u914d\uff0c\u56e0\u6b64\u4f1a\u505c\u6b62\u8bfb\u53d6\u53e6\u4e00\u4fa7\u3002\u8fd9\u6837\u4fbf\u672a\u8bfb\u53d6\u8be5\u5b50\u8282\u70b9\u7684\u5168\u90e8\u884c\uff0c\u7c7b\u4f3c LIMIT \u7684\u60c5\u51b5\u3002\u53e6\u5916\uff0c\u5916\u4fa7\uff08\u7b2c\u4e00\u4e2a\uff09\u5b50\u8282\u70b9\u6709\u91cd\u590d\u952e\u503c\u65f6\uff0c\u5185\u4fa7\uff08\u7b2c\u4e8c\u4e2a\uff09\u5b50\u8282\u70b9\u4f1a\u56de\u9000\u5e76\u91cd\u65b0\u626b\u63cf\u5339\u914d\u8be5\u952e\u503c\u7684\u884c\u3002EXPLAIN ANALYZE \u4f1a\u5c06\u5185\u4fa7\u91cd\u590d\u8f93\u51fa\u7684\u884c\u8ba1\u4f5c\u989d\u5916\u7684\u771f\u5b9e\u884c\u3002\u56e0\u6b64\u5916\u4fa7\u91cd\u590d\u503c\u5f88\u591a\u65f6\uff0c\u5185\u4fa7\u8ba1\u5212\u8282\u70b9\u62a5\u544a\u7684\u5b9e\u9645\u884c\u6570\u53ef\u80fd\u663e\u8457\u8d85\u8fc7\u5185\u4fa7\u5173\u7cfb\u4e2d\u7684\u5b9e\u9645\u884c\u6570\u3002", "\u4e0e\u975e\u5e76\u884c\u8ba1\u5212\u4e00\u6837\uff0c\u9a71\u52a8\u8868\u53ef\u4ee5\u901a\u8fc7\u5d4c\u5957\u5faa\u73af\u3001\u54c8\u5e0c\u8fde\u63a5\u6216\u5f52\u5e76\u8fde\u63a5\u4e0e\u4e00\u4e2a\u6216\u591a\u4e2a\u5176\u4ed6\u8868\u8fde\u63a5\u3002\u8fde\u63a5\u7684\u5185\u4fa7\u53ef\u4ee5\u662f\u89c4\u5212\u5668\u652f\u6301\u7684\u4efb\u4f55\u7c7b\u578b\u7684\u975e\u5e76\u884c\u8ba1\u5212\uff0c\u53ea\u8981\u5b83\u80fd\u591f\u5b89\u5168\u5730\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u4e2d\u8fd0\u884c\u3002\u6839\u636e\u8fde\u63a5\u7c7b\u578b\uff0c\u5185\u4fa7\u4e5f\u53ef\u4ee5\u662f\u5e76\u884c\u8ba1\u5212\u3002", "\u5728 \u5f52\u5e76\u8fde\u63a5 \u4e2d\uff0c\u5185\u4fa7\u59cb\u7ec8\u662f\u975e\u5e76\u884c\u8ba1\u5212\uff0c\u56e0\u6b64\u4f1a\u88ab\u5b8c\u6574\u6267\u884c\u3002\u8fd9\u53ef\u80fd\u6548\u7387\u4e0d\u9ad8\uff0c\u5c24\u5176\u662f\u5728\u5fc5\u987b\u6267\u884c\u6392\u5e8f\u65f6\uff0c\u56e0\u4e3a\u5de5\u4f5c\u91cf\u548c\u7ed3\u679c\u6570\u636e\u4f1a\u5728\u6bcf\u4e2a\u534f\u4f5c\u8fdb\u7a0b\u4e2d\u91cd\u590d\u3002", "PostgreSQL \u901a\u8fc7\u5206\u4e24\u4e2a\u9636\u6bb5\u8fdb\u884c\u805a\u5408\u6765\u652f\u6301\u5e76\u884c\u805a\u5408\u3002\u9996\u5148\uff0c\u6bcf\u4e2a\u53c2\u4e0e\u67e5\u8be2\u5e76\u884c\u90e8\u5206\u7684\u8fdb\u7a0b\u6267\u884c\u4e00\u4e2a\u805a\u5408\u6b65\u9aa4\uff0c\u4e3a\u8be5\u8fdb\u7a0b\u6240\u89c1\u5230\u7684\u6bcf\u4e2a\u5206\u7ec4\u4ea7\u751f\u4e00\u4e2a\u90e8\u5206\u7ed3\u679c\u3002\u8fd9\u5728\u8ba1\u5212\u4e2d\u4f53\u73b0\u4e3a\u4e00\u4e2a Partial Aggregate \u8282\u70b9\u3002\u7136\u540e\uff0c\u90e8\u5206\u7ed3\u679c\u901a\u8fc7 Gather \u6216 Gather Merge \u4f20\u9001\u7ed9\u9886\u5bfc\u8005\u3002\u6700\u540e\uff0c\u9886\u5bfc\u8005\u4f1a\u628a\u6765\u81ea\u6240\u6709\u5de5\u4f5c\u8fdb\u7a0b\u7684\u7ed3\u679c\u518d\u6b21\u805a\u5408\uff0c\u4ee5\u4ea7\u751f\u6700\u7ec8\u7ed3\u679c\u3002\u8fd9\u5728\u8ba1\u5212\u4e2d\u4f53\u73b0\u4e3a\u4e00\u4e2a Finalize Aggregate \u8282\u70b9\u3002"]}, {"title": "\u672c\u7248\u624b\u518c\u4e2d\u7684\u793a\u4f8b", "blocks": [{"code": "EXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=198.11..268.19 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..656.28 rows=101 width=244)\n         Filter: (unique1 < 100)\n   ->  Sort  (cost=197.83..200.33 rows=1000 width=244)\n         Sort Key: t2.unique2\n         ->  Seq Scan on onek t2  (cost=0.00..148.00 rows=1000 width=244)", "source": {"url": "/docs/13/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 13.23 \u00b7 using-explain", "sha256": "650fd8629382d5dc8f9f8412c50ec5f32442a9ad2f98ca88e5348a7c2bd0ac7a"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 13.23 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u53e6\u4e00\u79cd\u53ef\u80fd\u7684\u8fde\u63a5\u65b9\u5f0f\u662f\u5f52\u5e76\u8fde\u63a5\uff0c\u5982\u4e0b\u6240\u793a\uff1a"]}, {"code": "SET enable_sort = off;\n\nEXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=0.56..292.65 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..656.28 rows=101 width=244)\n         Filter: (unique1 < 100)\n   ->  Index Scan using onek_unique2 on onek t2  (cost=0.28..224.79 rows=1000 width=244)", "source": {"url": "/docs/13/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 13.23 \u00b7 using-explain", "sha256": "650fd8629382d5dc8f9f8412c50ec5f32442a9ad2f98ca88e5348a7c2bd0ac7a"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 13.23 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u89c2\u5bdf\u5907\u9009\u8ba1\u5212\u7684\u4e00\u79cd\u529e\u6cd5\uff0c\u662f\u4f7f\u7528\u7b2c 19.7.1 \u8282\u7684\u542f\u7528\uff0f\u7981\u7528\u6807\u5fd7\uff0c\u5f3a\u5236\u89c4\u5212\u5668\u5ffd\u7565\u5b83\u8ba4\u4e3a\u4ee3\u4ef7\u6700\u4f4e\u7684\u7b56\u7565\u3002\u8fd9\u79cd\u5de5\u5177\u8f83\u4e3a\u7c97\u7565\uff0c\u4f46\u5f88\u6709\u7528\uff0c\u53e6\u89c1\u7b2c 14.3 \u8282\u3002\u4f8b\u5982\uff0c\u5982\u679c\u4e0d\u786e\u5b9a\u524d\u4f8b\u4e2d\u5bf9 onek \u8868\u91c7\u7528\u987a\u5e8f\u626b\u63cf\u518d\u6392\u5e8f\u662f\u5426\u6700\u4f73\uff0c\u53ef\u4ee5\u5c1d\u8bd5\uff1a"]}]}, {"title": "\u6267\u884c\u5668\u5b9e\u73b0\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u5bf9\u6ee1\u8db3 ((= outerKey innerKey) ...) \u5f62\u5f0f\u8fde\u63a5\u6761\u4ef6\u7684\u5185\u5916\u4fa7\u5143\u7ec4\u6267\u884c\u8fde\u63a5\u3002\u8fde\u63a5\u6761\u4ef6\u5217\u8868\u7531\u67e5\u8be2\u89c4\u5212\u5668\u63d0\u4f9b\uff0c\u53ef\u4ee5\u5305\u542b\u591a\u4e2a (= outerKey innerKey) \u6761\u4ef6\uff0c\u4ee5\u652f\u6301\u590d\u5408\u6392\u5e8f\u952e\u3002", "\u4e0d\u8fc7\uff0c\u67e5\u8be2\u6267\u884c\u5668\u9700\u8981\u5224\u65ad\u5916\u4fa7\u5143\u7ec4\u662f\u5426\u201c\u5927\u4e8e\uff0f\u5c0f\u4e8e\u201d\u5185\u4fa7\u5143\u7ec4\uff0c\u4ee5\u4fbf\u201c\u540c\u6b65\u201d\u4e24\u4e2a\u5173\u7cfb\u3002\u4f8b\u5982\uff0c\u8003\u8651\u4ee5\u4e0b\u5173\u7cfb\uff1a", "outer: (0 ^1 1 2 5 5 5 6 6 7) current tuple: 1 inner: (1 ^3 5 5 5 5 6) current tuple: 3", "\u4e3a\u7ee7\u7eed\u5f52\u5e76\u8fde\u63a5\uff0c\u6267\u884c\u5668\u9700\u8981\u626b\u63cf\u5185\u5916\u4fa7\u5173\u7cfb\uff0c\u76f4\u5230\u627e\u5230\u5339\u914d\u7684\u5143\u7ec4 5\u3002\u5b83\u9700\u8981\u77e5\u9053\u5f53\u524d\u5185\u4fa7\u5143\u7ec4 3\u201c\u5927\u4e8e\u201d\u5916\u4fa7\u5143\u7ec4 1\uff0c\u56e0\u6b64\u5e94\u5148\u626b\u63cf\u5916\u4fa7\u5173\u7cfb\u4ee5\u5bfb\u627e\u5339\u914d\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002", "\u56e0\u6b64\uff0c\u4e0d\u76f4\u63a5\u6267\u884c\u5f52\u5e76\u8fde\u63a5\u6761\u4ef6\uff0c\u800c\u662f\u5206\u522b\u6c42\u503c\u5de6\u53f3\u952e\u8868\u8fbe\u5f0f\uff0c\u518d\u9010\u5217\u6bd4\u8f83\uff08\u53c2\u89c1 MJCompare\uff09\u3002\u89c4\u5212\u5668\u63d0\u4f9b\u8db3\u591f\u7684\u8f93\u5165\u6392\u5e8f\u4fe1\u606f\uff0c\u8ba9\u6267\u884c\u5668\u786e\u5b9a\u6bd4\u8f83\u65b9\u6cd5\u3002\u53ef\u4ee5\u4f7f\u7528\u76f8\u5e94\u7684 B-tree \u6bd4\u8f83\u51fd\u6570\uff0c\u56e0\u4e3a Postgres \u7684\u6392\u5e8f\u8bed\u4e49\u4ec5\u7531 B-tree \u64cd\u4f5c\u7b26\u5bb6\u65cf\u5b9a\u4e49\u3002"]}, {"code": "case T_MergeJoin:\n\t\t\tpname = \"Merge\";\t/* \"Join\" gets added by jointype switch */\n\t\t\tsname = \"Merge Join\";\n\t\t\tbreak;", "title": "\u6838\u5fc3\u6e90\u7801\u4e2d\u7684 EXPLAIN \u6807\u8bc6"}], "strategies": [], "description": ["\u4f7f\u7528\u5f52\u5e76\u6761\u4ef6\u8fde\u63a5\u6709\u5e8f\u8f93\u5165\u6d41\u3002"], "localization": {"status": "complete", "sources": [{"url": "/docs/13/parallel-plans.html", "method": "same-major semantic node", "sha256": "bbbbbd9cc27db6811c388e9c4951a9641c48871942bc709cec203e4271518c50", "language": "zh", "matched_nodes": ["#PARALLEL-PLANS/div[4]/div[2]/ul[0]/li[1]", "#PARALLEL-PLANS/div[4]/p[1]", "#PARALLEL-PLANS/div[5]/p[1]"]}], "language": "zh", "original_text": {"/versions/13/description/0": "Joins ordered input streams using merge clauses.", "/versions/13/facts/0/label": "Core node tag", "/versions/13/facts/1/label": "Structured EXPLAIN Node Type", "/versions/13/facts/2/label": "Inputs", "/versions/13/facts/2/value": "Ordered outer and inner child plans", "/versions/13/facts/3/label": "Output", "/versions/13/facts/3/value": "Joined tuples according to the selected join type", "/versions/13/facts/4/label": "Executor initializer", "/versions/13/facts/5/label": "Memory mechanism", "/versions/13/tables/0/title": "EXPLAIN labels in this source build", "/versions/13/related/1/label": "Using EXPLAIN", "/versions/13/related/2/label": "Parallel plans", "/versions/13/sections/0/title": "EXPLAIN names and attributes", "/versions/13/sections/1/title": "Memory and temporary storage", "/versions/13/sections/2/title": "Parallel execution and instrumentation", "/versions/13/sections/3/title": "Same-version manual discussion", "/versions/13/sections/4/title": "Examples from this manual build", "/versions/13/sections/5/title": "Executor implementation notes", "/versions/13/sections/6/title": "EXPLAIN identity in core source", "/versions/13/memory/description": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/13/sections/0/paragraphs/0": "Structured formats use the Node Type above. Text-format spellings can also include operation, strategy, join type, scan direction or aggregation-stage attributes.", "/versions/13/sections/0/paragraphs/1": "Text names recorded by this source: Merge.", "/versions/13/sections/0/paragraphs/2": "Parallel-aware and parallel-safe are different plan properties. A node running inside a parallel worker is not necessarily a parallel-aware node.", "/versions/13/sections/1/paragraphs/0": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/13/sections/2/paragraphs/0": "The source callbacks below can coordinate execution or collect worker instrumentation. Their presence is not a blanket claim that this node supports a shared parallel scan or shared state.", "/versions/13/sections/2/paragraphs/1": "Callbacks in this build: none extracted from this node implementation.", "/versions/13/sections/3/paragraphs/0": "Merge join requires its input data to be sorted on the join keys. In this plan the tenk1 data is sorted by using an index scan to visit the rows in the correct order, but a sequential scan and sort is preferred for onek , because there are many more rows to be visited in that table. (Sequential-scan-and-sort frequently beats an index scan for sorting many rows, because of the nonsequential disk access required by the index scan.)", "/versions/13/sections/3/paragraphs/1": "Merge joins also have measurement artifacts that can confuse the unwary. A merge join will stop reading one input if it's exhausted the other input and the next key value in the one input is greater than the last key value of the other input; in such a case there can be no more matches and so no need to scan the rest of the first input. This results in not reading all of one child, with results like those mentioned for LIMIT . Also, if the outer (first) child contains rows with duplicate key values, the inner (second) child is backed up and rescanned for the portion of its rows matching that key value. EXPLAIN ANALYZE counts these repeated emissions of the same inner rows as if they were real additional rows. When there are many outer duplicates, the reported actual row count for the inner child plan node can be significantly larger than the number of rows that are actually in the inner relation.", "/versions/13/sections/3/paragraphs/2": "Just as in a non-parallel plan, the driving table may be joined to one or more other tables using a nested loop, hash join, or merge join. The inner side of the join may be any kind of non-parallel plan that is otherwise supported by the planner provided that it is safe to run within a parallel worker. Depending on the join type, the inner side may also be a parallel plan.", "/versions/13/sections/3/paragraphs/3": "In a merge join , the inner side is always a non-parallel plan and therefore executed in full. This may be inefficient, especially if a sort must be performed, because the work and resulting data are duplicated in every cooperating process.", "/versions/13/sections/3/paragraphs/4": "PostgreSQL supports parallel aggregation by aggregating in two stages. First, each process participating in the parallel portion of the query performs an aggregation step, producing a partial result for each group of which that process is aware. This is reflected in the plan as a Partial Aggregate node. Second, the partial results are transferred to the leader via Gather or Gather Merge . Finally, the leader re-aggregates the results across all workers in order to produce the final result. This is reflected in the plan as a Finalize Aggregate node.", "/versions/13/sections/5/paragraphs/0": "Merge-join is done by joining the inner and outer tuples satisfying join clauses of the form ((= outerKey innerKey) ...). The join clause list is provided by the query planner and may contain more than one (= outerKey innerKey) clause (for composite sort key).", "/versions/13/sections/5/paragraphs/1": "However, the query executor needs to know whether an outer tuple is \"greater/smaller\" than an inner tuple so that it can \"synchronize\" the two relations. For example, consider the following relations:", "/versions/13/sections/5/paragraphs/3": "To continue the merge-join, the executor needs to scan both inner and outer relations till the matching tuples 5. It needs to know that currently inner tuple 3 is \"greater\" than outer tuple 1 and therefore it should scan the outer relation first to find a matching tuple and so on.", "/versions/13/sections/5/paragraphs/4": "Therefore, rather than directly executing the merge join clauses, we evaluate the left and right key expressions separately and then compare the columns one at a time (see MJCompare). The planner passes us enough information about the sort ordering of the inputs to allow us to determine how to make the comparison. We may use the appropriate btree comparison function, since Postgres' only notion of ordering is specified by btree opfamilies.", "/versions/13/tables/0/columns/0/label": "Text-format label", "/versions/13/tables/0/columns/1/label": "Structured node identity", "/versions/13/sections/4/blocks/0/paragraphs/0": "Example copied from the PostgreSQL 13.23 manual; it was not executed for this collection.", "/versions/13/sections/4/blocks/0/paragraphs/1": "Another possible type of join is a merge join, illustrated here:", "/versions/13/sections/4/blocks/1/paragraphs/0": "Example copied from the PostgreSQL 13.23 manual; it was not executed for this collection.", "/versions/13/sections/4/blocks/1/paragraphs/1": "One way to look at variant plans is to force the planner to disregard whatever strategy it thought was the cheapest, using the enable/disable flags described in Section 19.7.1 . (This is a crude tool, but useful. See also Section 14.3 .) For example, if we're unconvinced that sequential-scan-and-sort is the best way to deal with table onek in the previous example, we could try"}, "fallback_fields": [], "source_language": "en", "original_snapshot_sha256": "c623eb9ef82715af6cc7eae2a30151f66cd03f13fde900d8cb038d59de3d41a4"}, "evidence_kind": "source and documentation", "explain_names": ["Merge"], "partial_modes": [], "comparison_data": {"node_tag": "T_MergeJoin", "strategies": [], "text_names": ["Merge"], "initializer": "ExecInitMergeJoin", "partial_modes": [], "memory_mechanism": "unclassified", "parallel_callbacks": []}, "comparison_hash": "b17771ee4d48585afbaba91552e5eb00f05a4b6784aa491387217937a4a30511", "explain_prefixes": ["Parallel"], "runtime_verified": false, "source_inventory": {"explain": "src/backend/commands/explain.c", "executor": "src/backend/executor/execProcnode.c", "implementation": "src/backend/executor/nodeMergejoin.c"}, "parallel_callbacks": []}, "14": {"facts": [{"label": "\u6838\u5fc3\u8282\u70b9\u6807\u7b7e", "value": "T_MergeJoin"}, {"label": "\u7ed3\u6784\u5316 EXPLAIN \u8282\u70b9\u7c7b\u578b", "value": "Merge Join"}, {"label": "\u8f93\u5165", "value": "\u6709\u5e8f\u7684\u5916\u4fa7\u548c\u5185\u4fa7\u5b50\u8ba1\u5212"}, {"label": "\u8f93\u51fa", "value": "\u6309\u6240\u9009\u8fde\u63a5\u7c7b\u578b\u751f\u6210\u7684\u8fde\u63a5\u5143\u7ec4"}, {"label": "\u6267\u884c\u5668\u521d\u59cb\u5316\u51fd\u6570", "value": "ExecInitMergeJoin"}, {"label": "\u5185\u5b58\u673a\u5236", "value": "unclassified"}], "memory": {"evidence": [{"url": "https://ftp.postgresql.org/pub/source/v14.24/postgresql-14.24.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "9efa6c854338ab3f9b1df5eae3e06cb9c4fa9ede0f6ef7ed39048c13803e5350", "archive_sha256": "a7fa7ed3d558172355f51406097a7bd4f6b473be80f311ef7cda96bf383d8897"}], "mechanism": "unclassified", "description": "\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002", "source_notes": []}, "tables": [{"key": "explain-labels", "rows": [{"label": "Merge", "identity": "Merge Join"}], "title": "\u672c\u6784\u5efa\u4e2d\u7684 EXPLAIN \u6807\u7b7e", "columns": [{"key": "label", "label": "\u6587\u672c\u683c\u5f0f\u6807\u7b7e"}, {"key": "identity", "label": "\u7ed3\u6784\u5316\u8282\u70b9\u6807\u8bc6"}]}], "related": [{"url": "/wiki/sql/explain/?v=14", "label": "EXPLAIN"}, {"url": "/docs/14/using-explain.html", "label": "\u4f7f\u7528 EXPLAIN"}, {"url": "/docs/14/parallel-plans.html", "label": "\u5e76\u884c\u8ba1\u5212"}, {"url": "/wiki/guc/enable_mergejoin/?v=14", "label": "enable_mergejoin"}], "release": {"ref": "PostgreSQL 14.24 source archive", "label": "14.24", "major": "14", "channel": "stable", "revision": "a7fa7ed3d558172355f51406097a7bd4f6b473be80f311ef7cda96bf383d8897", "source_url": "https://ftp.postgresql.org/pub/source/v14.24/postgresql-14.24.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "https://ftp.postgresql.org/pub/source/v14.24/postgresql-14.24.tar.bz2", "line": 1214, "path": "src/backend/commands/explain.c", "label": "src/backend/commands/explain.c:1214", "sha256": "e091be4e2a083b8dea39ccd09beedede22c1716ef974da66c214a44f48be8c41", "archive_sha256": "a7fa7ed3d558172355f51406097a7bd4f6b473be80f311ef7cda96bf383d8897"}, {"url": "https://ftp.postgresql.org/pub/source/v14.24/postgresql-14.24.tar.bz2", "line": 302, "path": "src/backend/executor/execProcnode.c", "label": "src/backend/executor/execProcnode.c:302", "sha256": "72da1c5ad457f1d92a39ab73531701794df858419e3b89d6e6cb7079634e68fa", "archive_sha256": "a7fa7ed3d558172355f51406097a7bd4f6b473be80f311ef7cda96bf383d8897"}, {"url": "https://ftp.postgresql.org/pub/source/v14.24/postgresql-14.24.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "9efa6c854338ab3f9b1df5eae3e06cb9c4fa9ede0f6ef7ed39048c13803e5350", "archive_sha256": "a7fa7ed3d558172355f51406097a7bd4f6b473be80f311ef7cda96bf383d8897"}, {"url": "https://ftp.postgresql.org/pub/source/v14.24/postgresql-14.24.tar.bz2", "path": "src/include/nodes/plannodes.h", "label": "src/include/nodes/plannodes.h", "sha256": "302f51a16b570dba7ec4e7bc045f7df5800d21630280354d1a24025f3baec75d", "archive_sha256": "a7fa7ed3d558172355f51406097a7bd4f6b473be80f311ef7cda96bf383d8897"}, {"url": "https://pg.center/docs/14/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 14.24 \u00b7 using-explain", "sha256": "7f5ab59cb21a035ada45ea3426c5d1cca3f781273483677f73fdd76753555206", "language": "en", "original_url": "/docs/14/using-explain.html#USING-EXPLAIN-BASICS"}, {"url": "https://pg.center/docs/14/using-explain.html#USING-EXPLAIN-CAVEATS", "path": "using-explain.html", "label": "PostgreSQL 14.24 \u00b7 using-explain", "sha256": "7f5ab59cb21a035ada45ea3426c5d1cca3f781273483677f73fdd76753555206", "language": "en", "original_url": "/docs/14/using-explain.html#USING-EXPLAIN-CAVEATS"}, {"url": "https://pg.center/docs/14/parallel-plans.html#PARALLEL-JOINS", "path": "parallel-plans.html", "label": "PostgreSQL 14.24 \u00b7 parallel-plans", "sha256": "71fc3525781b74150364925e123cd8598fdebe0e05326706f2bc2e1ffa0b88a4", "language": "en", "original_url": "/docs/14/parallel-plans.html#PARALLEL-JOINS"}, {"url": "https://pg.center/docs/14/parallel-plans.html#PARALLEL-AGGREGATION", "path": "parallel-plans.html", "label": "PostgreSQL 14.24 \u00b7 parallel-plans", "sha256": "71fc3525781b74150364925e123cd8598fdebe0e05326706f2bc2e1ffa0b88a4", "language": "en", "original_url": "/docs/14/parallel-plans.html#PARALLEL-AGGREGATION"}], "node_tag": "T_MergeJoin", "sections": [{"title": "EXPLAIN \u540d\u79f0\u4e0e\u5c5e\u6027", "paragraphs": ["\u7ed3\u6784\u5316\u683c\u5f0f\u4f7f\u7528\u4e0a\u8ff0 Node Type\u3002\u6587\u672c\u683c\u5f0f\u540d\u79f0\u8fd8\u53ef\u80fd\u5305\u542b\u64cd\u4f5c\u3001\u7b56\u7565\u3001\u8fde\u63a5\u7c7b\u578b\u3001\u626b\u63cf\u65b9\u5411\u6216\u805a\u5408\u9636\u6bb5\u5c5e\u6027\u3002", "\u6b64\u6e90\u7801\u8bb0\u5f55\u7684\u6587\u672c\u540d\u79f0\uff1aMerge.", "\u5e76\u884c\u611f\u77e5\u4e0e\u5e76\u884c\u5b89\u5168\u662f\u4e0d\u540c\u7684\u8ba1\u5212\u5c5e\u6027\u3002\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u5185\u8fd0\u884c\u7684\u8282\u70b9\u4e0d\u4e00\u5b9a\u662f\u5e76\u884c\u611f\u77e5\u8282\u70b9\u3002"]}, {"title": "\u5185\u5b58\u4e0e\u4e34\u65f6\u5b58\u50a8", "paragraphs": ["\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002"]}, {"title": "\u5e76\u884c\u6267\u884c\u4e0e\u8fd0\u884c\u4fe1\u606f\u91c7\u96c6", "paragraphs": ["\u4ee5\u4e0b\u6e90\u7801\u56de\u8c03\u53ef\u4ee5\u534f\u8c03\u6267\u884c\u6216\u6536\u96c6\u5de5\u4f5c\u8fdb\u7a0b\u7684\u6d4b\u91cf\u6570\u636e\u3002\u56de\u8c03\u5b58\u5728\u4e0d\u4ee3\u8868\u8be5\u8282\u70b9\u666e\u904d\u652f\u6301\u5171\u4eab\u5e76\u884c\u626b\u63cf\u6216\u5171\u4eab\u72b6\u6001\u3002", "\u6b64\u6784\u5efa\u7684\u56de\u8c03\uff1anone extracted from this node implementation."]}, {"title": "\u540c\u7248\u672c\u624b\u518c\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u8981\u6c42\u8f93\u5165\u6309\u8fde\u63a5\u952e\u6392\u5e8f\u3002\u6b64\u8ba1\u5212\u901a\u8fc7\u7d22\u5f15\u626b\u63cf\u6309\u987a\u5e8f\u8bfb\u53d6 tenk1\uff1b\u5bf9\u4e8e onek\uff0c\u5219\u503e\u5411\u4e8e\u987a\u5e8f\u626b\u63cf\u540e\u6392\u5e8f\uff0c\u56e0\u4e3a\u8be5\u8868\u8981\u8bbf\u95ee\u7684\u884c\u66f4\u591a\u3002\uff08\u5bf9\u5927\u91cf\u884c\u6392\u5e8f\u65f6\uff0c\u987a\u5e8f\u626b\u63cf\u52a0\u6392\u5e8f\u5e38\u5e38\u4f18\u4e8e\u7d22\u5f15\u626b\u63cf\uff0c\u56e0\u4e3a\u540e\u8005\u9700\u8981\u975e\u987a\u5e8f\u78c1\u76d8\u8bbf\u95ee\u3002\uff09", "\u5f52\u5e76\u8fde\u63a5\u7684\u6d4b\u91cf\u7ed3\u679c\u4e5f\u53ef\u80fd\u4ea7\u751f\u8bef\u5bfc\u3002\u82e5\u4e00\u4fa7\u8f93\u5165\u5df2\u8017\u5c3d\uff0c\u53e6\u4e00\u4fa7\u7684\u4e0b\u4e00\u4e2a\u952e\u503c\u53c8\u5927\u4e8e\u5df2\u8017\u5c3d\u8f93\u5165\u7684\u6700\u540e\u4e00\u4e2a\u952e\u503c\uff0c\u5c31\u4e0d\u4f1a\u518d\u6709\u5339\u914d\uff0c\u56e0\u6b64\u4f1a\u505c\u6b62\u8bfb\u53d6\u53e6\u4e00\u4fa7\u3002\u8fd9\u6837\u4fbf\u672a\u8bfb\u53d6\u8be5\u5b50\u8282\u70b9\u7684\u5168\u90e8\u884c\uff0c\u7c7b\u4f3c LIMIT \u7684\u60c5\u51b5\u3002\u53e6\u5916\uff0c\u5916\u4fa7\uff08\u7b2c\u4e00\u4e2a\uff09\u5b50\u8282\u70b9\u6709\u91cd\u590d\u952e\u503c\u65f6\uff0c\u5185\u4fa7\uff08\u7b2c\u4e8c\u4e2a\uff09\u5b50\u8282\u70b9\u4f1a\u56de\u9000\u5e76\u91cd\u65b0\u626b\u63cf\u5339\u914d\u8be5\u952e\u503c\u7684\u884c\u3002EXPLAIN ANALYZE \u4f1a\u5c06\u5185\u4fa7\u91cd\u590d\u8f93\u51fa\u7684\u884c\u8ba1\u4f5c\u989d\u5916\u7684\u771f\u5b9e\u884c\u3002\u56e0\u6b64\u5916\u4fa7\u91cd\u590d\u503c\u5f88\u591a\u65f6\uff0c\u5185\u4fa7\u8ba1\u5212\u8282\u70b9\u62a5\u544a\u7684\u5b9e\u9645\u884c\u6570\u53ef\u80fd\u663e\u8457\u8d85\u8fc7\u5185\u4fa7\u5173\u7cfb\u4e2d\u7684\u5b9e\u9645\u884c\u6570\u3002", "\u4e0e\u975e\u5e76\u884c\u8ba1\u5212\u4e00\u6837\uff0c\u9a71\u52a8\u8868\u53ef\u4ee5\u901a\u8fc7\u5d4c\u5957\u5faa\u73af\u3001\u54c8\u5e0c\u8fde\u63a5\u6216\u5f52\u5e76\u8fde\u63a5\u4e0e\u4e00\u4e2a\u6216\u591a\u4e2a\u5176\u4ed6\u8868\u8fde\u63a5\u3002\u8fde\u63a5\u7684\u5185\u4fa7\u53ef\u4ee5\u662f\u89c4\u5212\u5668\u652f\u6301\u7684\u4efb\u4f55\u7c7b\u578b\u7684\u975e\u5e76\u884c\u8ba1\u5212\uff0c\u53ea\u8981\u5b83\u80fd\u591f\u5b89\u5168\u5730\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u4e2d\u8fd0\u884c\u3002\u6839\u636e\u8fde\u63a5\u7c7b\u578b\uff0c\u5185\u4fa7\u4e5f\u53ef\u4ee5\u662f\u5e76\u884c\u8ba1\u5212\u3002", "\u5728 \u5f52\u5e76\u8fde\u63a5 \u4e2d\uff0c\u5185\u4fa7\u59cb\u7ec8\u662f\u975e\u5e76\u884c\u8ba1\u5212\uff0c\u56e0\u6b64\u4f1a\u88ab\u5b8c\u6574\u6267\u884c\u3002\u8fd9\u53ef\u80fd\u6548\u7387\u4e0d\u9ad8\uff0c\u5c24\u5176\u662f\u5728\u5fc5\u987b\u6267\u884c\u6392\u5e8f\u65f6\uff0c\u56e0\u4e3a\u5de5\u4f5c\u91cf\u548c\u7ed3\u679c\u6570\u636e\u4f1a\u5728\u6bcf\u4e2a\u534f\u4f5c\u8fdb\u7a0b\u4e2d\u91cd\u590d\u3002", "PostgreSQL \u901a\u8fc7\u5206\u4e24\u4e2a\u9636\u6bb5\u8fdb\u884c\u805a\u5408\u6765\u652f\u6301\u5e76\u884c\u805a\u5408\u3002\u9996\u5148\uff0c\u6bcf\u4e2a\u53c2\u4e0e\u67e5\u8be2\u5e76\u884c\u90e8\u5206\u7684\u8fdb\u7a0b\u6267\u884c\u4e00\u4e2a\u805a\u5408\u6b65\u9aa4\uff0c\u4e3a\u8be5\u8fdb\u7a0b\u6240\u89c1\u5230\u7684\u6bcf\u4e2a\u5206\u7ec4\u4ea7\u751f\u4e00\u4e2a\u90e8\u5206\u7ed3\u679c\u3002\u8fd9\u5728\u8ba1\u5212\u4e2d\u4f53\u73b0\u4e3a\u4e00\u4e2a Partial Aggregate \u8282\u70b9\u3002\u7136\u540e\uff0c\u90e8\u5206\u7ed3\u679c\u901a\u8fc7 Gather \u6216 Gather Merge \u4f20\u9001\u7ed9\u9886\u5bfc\u8005\u3002\u6700\u540e\uff0c\u9886\u5bfc\u8005\u4f1a\u628a\u6765\u81ea\u6240\u6709\u5de5\u4f5c\u8fdb\u7a0b\u7684\u7ed3\u679c\u518d\u6b21\u805a\u5408\uff0c\u4ee5\u4ea7\u751f\u6700\u7ec8\u7ed3\u679c\u3002\u8fd9\u5728\u8ba1\u5212\u4e2d\u4f53\u73b0\u4e3a\u4e00\u4e2a Finalize Aggregate \u8282\u70b9\u3002"]}, {"title": "\u672c\u7248\u624b\u518c\u4e2d\u7684\u793a\u4f8b", "blocks": [{"code": "EXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=198.11..268.19 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..656.28 rows=101 width=244)\n         Filter: (unique1 < 100)\n   ->  Sort  (cost=197.83..200.33 rows=1000 width=244)\n         Sort Key: t2.unique2\n         ->  Seq Scan on onek t2  (cost=0.00..148.00 rows=1000 width=244)", "source": {"url": "/docs/14/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 14.24 \u00b7 using-explain", "sha256": "7f5ab59cb21a035ada45ea3426c5d1cca3f781273483677f73fdd76753555206"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 14.24 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u53e6\u4e00\u79cd\u53ef\u80fd\u7684\u8fde\u63a5\u65b9\u5f0f\u662f\u5f52\u5e76\u8fde\u63a5\uff0c\u5982\u4e0b\u6240\u793a\uff1a"]}, {"code": "SET enable_sort = off;\n\nEXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=0.56..292.65 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..656.28 rows=101 width=244)\n         Filter: (unique1 < 100)\n   ->  Index Scan using onek_unique2 on onek t2  (cost=0.28..224.79 rows=1000 width=244)", "source": {"url": "/docs/14/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 14.24 \u00b7 using-explain", "sha256": "7f5ab59cb21a035ada45ea3426c5d1cca3f781273483677f73fdd76753555206"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 14.24 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u8003\u5bdf\u5176\u4ed6\u8ba1\u5212\u7684\u4e00\u79cd\u65b9\u6cd5\uff0c\u662f\u7528\u7b2c 20.7.1 \u8282\u4e2d\u7684\u542f\u7528/\u7981\u7528\u6807\u5fd7\uff0c\u5f3a\u5236\u89c4\u5212\u5668\u5ffd\u7565\u5b83\u539f\u672c\u8ba4\u4e3a\u6210\u672c\u6700\u4f4e\u7684\u7b56\u7565\u3002\uff08\u8fd9\u79cd\u65b9\u6cd5\u6bd4\u8f83\u7c97\u7cd9\uff0c\u4f46\u5f88\u6709\u7528\uff1b\u53e6\u89c1\u7b2c 14.3 \u8282\u3002\uff09\u4f8b\u5982\uff0c\u82e5\u4e0d\u786e\u4fe1\u4e0a\u4f8b\u5904\u7406 onek \u7684\u6700\u4f73\u65b9\u5f0f\u662f\u987a\u5e8f\u626b\u63cf\u52a0\u6392\u5e8f\uff0c\u53ef\u4ee5\u5c1d\u8bd5\uff1a"]}]}, {"title": "\u6267\u884c\u5668\u5b9e\u73b0\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u5bf9\u6ee1\u8db3 ((= outerKey innerKey) ...) \u5f62\u5f0f\u8fde\u63a5\u6761\u4ef6\u7684\u5185\u5916\u4fa7\u5143\u7ec4\u6267\u884c\u8fde\u63a5\u3002\u8fde\u63a5\u6761\u4ef6\u5217\u8868\u7531\u67e5\u8be2\u89c4\u5212\u5668\u63d0\u4f9b\uff0c\u53ef\u4ee5\u5305\u542b\u591a\u4e2a (= outerKey innerKey) \u6761\u4ef6\uff0c\u4ee5\u652f\u6301\u590d\u5408\u6392\u5e8f\u952e\u3002", "\u4e0d\u8fc7\uff0c\u67e5\u8be2\u6267\u884c\u5668\u9700\u8981\u5224\u65ad\u5916\u4fa7\u5143\u7ec4\u662f\u5426\u201c\u5927\u4e8e\uff0f\u5c0f\u4e8e\u201d\u5185\u4fa7\u5143\u7ec4\uff0c\u4ee5\u4fbf\u201c\u540c\u6b65\u201d\u4e24\u4e2a\u5173\u7cfb\u3002\u4f8b\u5982\uff0c\u8003\u8651\u4ee5\u4e0b\u5173\u7cfb\uff1a", "outer: (0 ^1 1 2 5 5 5 6 6 7) current tuple: 1 inner: (1 ^3 5 5 5 5 6) current tuple: 3", "\u4e3a\u7ee7\u7eed\u5f52\u5e76\u8fde\u63a5\uff0c\u6267\u884c\u5668\u9700\u8981\u626b\u63cf\u5185\u5916\u4fa7\u5173\u7cfb\uff0c\u76f4\u5230\u627e\u5230\u5339\u914d\u7684\u5143\u7ec4 5\u3002\u5b83\u9700\u8981\u77e5\u9053\u5f53\u524d\u5185\u4fa7\u5143\u7ec4 3\u201c\u5927\u4e8e\u201d\u5916\u4fa7\u5143\u7ec4 1\uff0c\u56e0\u6b64\u5e94\u5148\u626b\u63cf\u5916\u4fa7\u5173\u7cfb\u4ee5\u5bfb\u627e\u5339\u914d\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002", "\u56e0\u6b64\uff0c\u4e0d\u76f4\u63a5\u6267\u884c\u5f52\u5e76\u8fde\u63a5\u6761\u4ef6\uff0c\u800c\u662f\u5206\u522b\u6c42\u503c\u5de6\u53f3\u952e\u8868\u8fbe\u5f0f\uff0c\u518d\u9010\u5217\u6bd4\u8f83\uff08\u53c2\u89c1 MJCompare\uff09\u3002\u89c4\u5212\u5668\u63d0\u4f9b\u8db3\u591f\u7684\u8f93\u5165\u6392\u5e8f\u4fe1\u606f\uff0c\u8ba9\u6267\u884c\u5668\u786e\u5b9a\u6bd4\u8f83\u65b9\u6cd5\u3002\u53ef\u4ee5\u4f7f\u7528\u76f8\u5e94\u7684 B-tree \u6bd4\u8f83\u51fd\u6570\uff0c\u56e0\u4e3a Postgres \u7684\u6392\u5e8f\u8bed\u4e49\u4ec5\u7531 B-tree \u64cd\u4f5c\u7b26\u5bb6\u65cf\u5b9a\u4e49\u3002"]}, {"code": "case T_MergeJoin:\n\t\t\tpname = \"Merge\";\t/* \"Join\" gets added by jointype switch */\n\t\t\tsname = \"Merge Join\";\n\t\t\tbreak;", "title": "\u6838\u5fc3\u6e90\u7801\u4e2d\u7684 EXPLAIN \u6807\u8bc6"}], "strategies": [], "description": ["\u4f7f\u7528\u5f52\u5e76\u6761\u4ef6\u8fde\u63a5\u6709\u5e8f\u8f93\u5165\u6d41\u3002"], "localization": {"status": "complete", "sources": [{"url": "/docs/14/parallel-plans.html", "method": "same-major semantic node", "sha256": "27ba0fab61ef7b5aa518b18597a7cd30f9560e5cf2b383016d31e59518892f88", "language": "zh", "matched_nodes": ["#PARALLEL-PLANS/div[4]/div[2]/ul[0]/li[1]", "#PARALLEL-PLANS/div[4]/p[1]", "#PARALLEL-PLANS/div[5]/p[1]"]}], "language": "zh", "original_text": {"/versions/14/description/0": "Joins ordered input streams using merge clauses.", "/versions/14/facts/0/label": "Core node tag", "/versions/14/facts/1/label": "Structured EXPLAIN Node Type", "/versions/14/facts/2/label": "Inputs", "/versions/14/facts/2/value": "Ordered outer and inner child plans", "/versions/14/facts/3/label": "Output", "/versions/14/facts/3/value": "Joined tuples according to the selected join type", "/versions/14/facts/4/label": "Executor initializer", "/versions/14/facts/5/label": "Memory mechanism", "/versions/14/tables/0/title": "EXPLAIN labels in this source build", "/versions/14/related/1/label": "Using EXPLAIN", "/versions/14/related/2/label": "Parallel plans", "/versions/14/sections/0/title": "EXPLAIN names and attributes", "/versions/14/sections/1/title": "Memory and temporary storage", "/versions/14/sections/2/title": "Parallel execution and instrumentation", "/versions/14/sections/3/title": "Same-version manual discussion", "/versions/14/sections/4/title": "Examples from this manual build", "/versions/14/sections/5/title": "Executor implementation notes", "/versions/14/sections/6/title": "EXPLAIN identity in core source", "/versions/14/memory/description": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/14/sections/0/paragraphs/0": "Structured formats use the Node Type above. Text-format spellings can also include operation, strategy, join type, scan direction or aggregation-stage attributes.", "/versions/14/sections/0/paragraphs/1": "Text names recorded by this source: Merge.", "/versions/14/sections/0/paragraphs/2": "Parallel-aware and parallel-safe are different plan properties. A node running inside a parallel worker is not necessarily a parallel-aware node.", "/versions/14/sections/1/paragraphs/0": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/14/sections/2/paragraphs/0": "The source callbacks below can coordinate execution or collect worker instrumentation. Their presence is not a blanket claim that this node supports a shared parallel scan or shared state.", "/versions/14/sections/2/paragraphs/1": "Callbacks in this build: none extracted from this node implementation.", "/versions/14/sections/3/paragraphs/0": "Merge join requires its input data to be sorted on the join keys. In this plan the tenk1 data is sorted by using an index scan to visit the rows in the correct order, but a sequential scan and sort is preferred for onek , because there are many more rows to be visited in that table. (Sequential-scan-and-sort frequently beats an index scan for sorting many rows, because of the nonsequential disk access required by the index scan.)", "/versions/14/sections/3/paragraphs/1": "Merge joins also have measurement artifacts that can confuse the unwary. A merge join will stop reading one input if it's exhausted the other input and the next key value in the one input is greater than the last key value of the other input; in such a case there can be no more matches and so no need to scan the rest of the first input. This results in not reading all of one child, with results like those mentioned for LIMIT . Also, if the outer (first) child contains rows with duplicate key values, the inner (second) child is backed up and rescanned for the portion of its rows matching that key value. EXPLAIN ANALYZE counts these repeated emissions of the same inner rows as if they were real additional rows. When there are many outer duplicates, the reported actual row count for the inner child plan node can be significantly larger than the number of rows that are actually in the inner relation.", "/versions/14/sections/3/paragraphs/2": "Just as in a non-parallel plan, the driving table may be joined to one or more other tables using a nested loop, hash join, or merge join. The inner side of the join may be any kind of non-parallel plan that is otherwise supported by the planner provided that it is safe to run within a parallel worker. Depending on the join type, the inner side may also be a parallel plan.", "/versions/14/sections/3/paragraphs/3": "In a merge join , the inner side is always a non-parallel plan and therefore executed in full. This may be inefficient, especially if a sort must be performed, because the work and resulting data are duplicated in every cooperating process.", "/versions/14/sections/3/paragraphs/4": "PostgreSQL supports parallel aggregation by aggregating in two stages. First, each process participating in the parallel portion of the query performs an aggregation step, producing a partial result for each group of which that process is aware. This is reflected in the plan as a Partial Aggregate node. Second, the partial results are transferred to the leader via Gather or Gather Merge . Finally, the leader re-aggregates the results across all workers in order to produce the final result. This is reflected in the plan as a Finalize Aggregate node.", "/versions/14/sections/5/paragraphs/0": "Merge-join is done by joining the inner and outer tuples satisfying join clauses of the form ((= outerKey innerKey) ...). The join clause list is provided by the query planner and may contain more than one (= outerKey innerKey) clause (for composite sort key).", "/versions/14/sections/5/paragraphs/1": "However, the query executor needs to know whether an outer tuple is \"greater/smaller\" than an inner tuple so that it can \"synchronize\" the two relations. For example, consider the following relations:", "/versions/14/sections/5/paragraphs/3": "To continue the merge-join, the executor needs to scan both inner and outer relations till the matching tuples 5. It needs to know that currently inner tuple 3 is \"greater\" than outer tuple 1 and therefore it should scan the outer relation first to find a matching tuple and so on.", "/versions/14/sections/5/paragraphs/4": "Therefore, rather than directly executing the merge join clauses, we evaluate the left and right key expressions separately and then compare the columns one at a time (see MJCompare). The planner passes us enough information about the sort ordering of the inputs to allow us to determine how to make the comparison. We may use the appropriate btree comparison function, since Postgres' only notion of ordering is specified by btree opfamilies.", "/versions/14/tables/0/columns/0/label": "Text-format label", "/versions/14/tables/0/columns/1/label": "Structured node identity", "/versions/14/sections/4/blocks/0/paragraphs/0": "Example copied from the PostgreSQL 14.24 manual; it was not executed for this collection.", "/versions/14/sections/4/blocks/0/paragraphs/1": "Another possible type of join is a merge join, illustrated here:", "/versions/14/sections/4/blocks/1/paragraphs/0": "Example copied from the PostgreSQL 14.24 manual; it was not executed for this collection.", "/versions/14/sections/4/blocks/1/paragraphs/1": "One way to look at variant plans is to force the planner to disregard whatever strategy it thought was the cheapest, using the enable/disable flags described in Section 20.7.1 . (This is a crude tool, but useful. See also Section 14.3 .) For example, if we're unconvinced that sequential-scan-and-sort is the best way to deal with table onek in the previous example, we could try"}, "fallback_fields": [], "source_language": "en", "original_snapshot_sha256": "15e9867f947952cd53b7f3e6f7b0c676f34a2b944869382a7c62131ed7ce44d8"}, "evidence_kind": "source and documentation", "explain_names": ["Merge"], "partial_modes": [], "comparison_data": {"node_tag": "T_MergeJoin", "strategies": [], "text_names": ["Merge"], "initializer": "ExecInitMergeJoin", "partial_modes": [], "memory_mechanism": "unclassified", "parallel_callbacks": []}, "comparison_hash": "b17771ee4d48585afbaba91552e5eb00f05a4b6784aa491387217937a4a30511", "explain_prefixes": ["Parallel", "Async"], "runtime_verified": false, "source_inventory": {"explain": "src/backend/commands/explain.c", "executor": "src/backend/executor/execProcnode.c", "implementation": "src/backend/executor/nodeMergejoin.c"}, "parallel_callbacks": []}, "15": {"facts": [{"label": "\u6838\u5fc3\u8282\u70b9\u6807\u7b7e", "value": "T_MergeJoin"}, {"label": "\u7ed3\u6784\u5316 EXPLAIN \u8282\u70b9\u7c7b\u578b", "value": "Merge Join"}, {"label": "\u8f93\u5165", "value": "\u6709\u5e8f\u7684\u5916\u4fa7\u548c\u5185\u4fa7\u5b50\u8ba1\u5212"}, {"label": "\u8f93\u51fa", "value": "\u6309\u6240\u9009\u8fde\u63a5\u7c7b\u578b\u751f\u6210\u7684\u8fde\u63a5\u5143\u7ec4"}, {"label": "\u6267\u884c\u5668\u521d\u59cb\u5316\u51fd\u6570", "value": "ExecInitMergeJoin"}, {"label": "\u5185\u5b58\u673a\u5236", "value": "unclassified"}], "memory": {"evidence": [{"url": "https://ftp.postgresql.org/pub/source/v15.19/postgresql-15.19.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "b91f72bd62b5a1d293aa18560ce7c5c2c01edb9731dc1285fbcf7270fc866ddd", "archive_sha256": "e1a64a87a46b825b88c082e4518161a47aab53c45694964f8ba1df28f7859f89"}], "mechanism": "unclassified", "description": "\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002", "source_notes": []}, "tables": [{"key": "explain-labels", "rows": [{"label": "Merge", "identity": "Merge Join"}], "title": "\u672c\u6784\u5efa\u4e2d\u7684 EXPLAIN \u6807\u7b7e", "columns": [{"key": "label", "label": "\u6587\u672c\u683c\u5f0f\u6807\u7b7e"}, {"key": "identity", "label": "\u7ed3\u6784\u5316\u8282\u70b9\u6807\u8bc6"}]}], "related": [{"url": "/wiki/sql/explain/?v=15", "label": "EXPLAIN"}, {"url": "/docs/15/using-explain.html", "label": "\u4f7f\u7528 EXPLAIN"}, {"url": "/docs/15/parallel-plans.html", "label": "\u5e76\u884c\u8ba1\u5212"}, {"url": "/wiki/guc/enable_mergejoin/?v=15", "label": "enable_mergejoin"}], "release": {"ref": "PostgreSQL 15.19 source archive", "label": "15.19", "major": "15", "channel": "stable", "revision": "e1a64a87a46b825b88c082e4518161a47aab53c45694964f8ba1df28f7859f89", "source_url": "https://ftp.postgresql.org/pub/source/v15.19/postgresql-15.19.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "https://ftp.postgresql.org/pub/source/v15.19/postgresql-15.19.tar.bz2", "line": 1217, "path": "src/backend/commands/explain.c", "label": "src/backend/commands/explain.c:1217", "sha256": "bb3b442d0f1b098aa8707335250102f027a596cd94117308bd16d1d36b258f5c", "archive_sha256": "e1a64a87a46b825b88c082e4518161a47aab53c45694964f8ba1df28f7859f89"}, {"url": "https://ftp.postgresql.org/pub/source/v15.19/postgresql-15.19.tar.bz2", "line": 302, "path": "src/backend/executor/execProcnode.c", "label": "src/backend/executor/execProcnode.c:302", "sha256": "19836c50a272741a4eac653541e655437c2e00710a541e5348d6a277d0669d7c", "archive_sha256": "e1a64a87a46b825b88c082e4518161a47aab53c45694964f8ba1df28f7859f89"}, {"url": "https://ftp.postgresql.org/pub/source/v15.19/postgresql-15.19.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "b91f72bd62b5a1d293aa18560ce7c5c2c01edb9731dc1285fbcf7270fc866ddd", "archive_sha256": "e1a64a87a46b825b88c082e4518161a47aab53c45694964f8ba1df28f7859f89"}, {"url": "https://ftp.postgresql.org/pub/source/v15.19/postgresql-15.19.tar.bz2", "path": "src/include/nodes/plannodes.h", "label": "src/include/nodes/plannodes.h", "sha256": "fb4a4c8165495299131173680bc02a950d88e1ff610231fd97997bc0c9afc1d7", "archive_sha256": "e1a64a87a46b825b88c082e4518161a47aab53c45694964f8ba1df28f7859f89"}, {"url": "https://pg.center/docs/15/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 15.19 \u00b7 using-explain", "sha256": "d1f509457c647da453d2575c772d91022a0f115dd84f9a3b20f5ff25a243648f", "language": "en", "original_url": "/docs/15/using-explain.html#USING-EXPLAIN-BASICS"}, {"url": "https://pg.center/docs/15/using-explain.html#USING-EXPLAIN-ANALYZE", "path": "using-explain.html", "label": "PostgreSQL 15.19 \u00b7 using-explain", "sha256": "d1f509457c647da453d2575c772d91022a0f115dd84f9a3b20f5ff25a243648f", "language": "en", "original_url": "/docs/15/using-explain.html#USING-EXPLAIN-ANALYZE"}, {"url": "https://pg.center/docs/15/using-explain.html#USING-EXPLAIN-CAVEATS", "path": "using-explain.html", "label": "PostgreSQL 15.19 \u00b7 using-explain", "sha256": "d1f509457c647da453d2575c772d91022a0f115dd84f9a3b20f5ff25a243648f", "language": "en", "original_url": "/docs/15/using-explain.html#USING-EXPLAIN-CAVEATS"}, {"url": "https://pg.center/docs/15/parallel-plans.html#PARALLEL-JOINS", "path": "parallel-plans.html", "label": "PostgreSQL 15.19 \u00b7 parallel-plans", "sha256": "ec9345488a15cdc05d3e0b0849763e2bf0b864ad17de786c5f023db5dab1ea96", "language": "en", "original_url": "/docs/15/parallel-plans.html#PARALLEL-JOINS"}], "node_tag": "T_MergeJoin", "sections": [{"title": "EXPLAIN \u540d\u79f0\u4e0e\u5c5e\u6027", "paragraphs": ["\u7ed3\u6784\u5316\u683c\u5f0f\u4f7f\u7528\u4e0a\u8ff0 Node Type\u3002\u6587\u672c\u683c\u5f0f\u540d\u79f0\u8fd8\u53ef\u80fd\u5305\u542b\u64cd\u4f5c\u3001\u7b56\u7565\u3001\u8fde\u63a5\u7c7b\u578b\u3001\u626b\u63cf\u65b9\u5411\u6216\u805a\u5408\u9636\u6bb5\u5c5e\u6027\u3002", "\u6b64\u6e90\u7801\u8bb0\u5f55\u7684\u6587\u672c\u540d\u79f0\uff1aMerge.", "\u5e76\u884c\u611f\u77e5\u4e0e\u5e76\u884c\u5b89\u5168\u662f\u4e0d\u540c\u7684\u8ba1\u5212\u5c5e\u6027\u3002\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u5185\u8fd0\u884c\u7684\u8282\u70b9\u4e0d\u4e00\u5b9a\u662f\u5e76\u884c\u611f\u77e5\u8282\u70b9\u3002"]}, {"title": "\u5185\u5b58\u4e0e\u4e34\u65f6\u5b58\u50a8", "paragraphs": ["\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002"]}, {"title": "\u5e76\u884c\u6267\u884c\u4e0e\u8fd0\u884c\u4fe1\u606f\u91c7\u96c6", "paragraphs": ["\u4ee5\u4e0b\u6e90\u7801\u56de\u8c03\u53ef\u4ee5\u534f\u8c03\u6267\u884c\u6216\u6536\u96c6\u5de5\u4f5c\u8fdb\u7a0b\u7684\u6d4b\u91cf\u6570\u636e\u3002\u56de\u8c03\u5b58\u5728\u4e0d\u4ee3\u8868\u8be5\u8282\u70b9\u666e\u904d\u652f\u6301\u5171\u4eab\u5e76\u884c\u626b\u63cf\u6216\u5171\u4eab\u72b6\u6001\u3002", "\u6b64\u6784\u5efa\u7684\u56de\u8c03\uff1anone extracted from this node implementation."]}, {"title": "\u540c\u7248\u672c\u624b\u518c\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u8981\u6c42\u8f93\u5165\u6309\u8fde\u63a5\u952e\u6392\u5e8f\u3002\u6b64\u8ba1\u5212\u901a\u8fc7\u7d22\u5f15\u626b\u63cf\u6309\u987a\u5e8f\u8bfb\u53d6 tenk1\uff1b\u5bf9\u4e8e onek\uff0c\u5219\u503e\u5411\u4e8e\u987a\u5e8f\u626b\u63cf\u540e\u6392\u5e8f\uff0c\u56e0\u4e3a\u8be5\u8868\u8981\u8bbf\u95ee\u7684\u884c\u66f4\u591a\u3002\uff08\u5bf9\u5927\u91cf\u884c\u6392\u5e8f\u65f6\uff0c\u987a\u5e8f\u626b\u63cf\u52a0\u6392\u5e8f\u5e38\u5e38\u4f18\u4e8e\u7d22\u5f15\u626b\u63cf\uff0c\u56e0\u4e3a\u540e\u8005\u9700\u8981\u975e\u987a\u5e8f\u78c1\u76d8\u8bbf\u95ee\u3002\uff09", "\u5982\u672c\u4f8b\u6240\u793a\uff0c\u67e5\u8be2\u4e3a INSERT\u3001UPDATE\u3001DELETE \u6216 MERGE \u547d\u4ee4\u65f6\uff0c\u5b9e\u9645\u5e94\u7528\u8868\u53d8\u66f4\u7684\u5de5\u4f5c\u7531\u9876\u5c42 Insert\u3001Update\u3001Delete \u6216 Merge \u8ba1\u5212\u8282\u70b9\u5b8c\u6210\u3002\u5176\u4e0b\u7684\u8ba1\u5212\u8282\u70b9\u8d1f\u8d23\u5b9a\u4f4d\u65e7\u884c\u548c\uff0f\u6216\u8ba1\u7b97\u65b0\u6570\u636e\u3002\u56e0\u6b64\uff0c\u4e0a\u4f8b\u4ecd\u91c7\u7528\u524d\u9762\u89c1\u8fc7\u7684\u4f4d\u56fe\u8868\u626b\u63cf\uff0c\u5176\u8f93\u51fa\u4f20\u7ed9 Update \u8282\u70b9\uff0c\u7531\u540e\u8005\u5b58\u50a8\u66f4\u65b0\u540e\u7684\u884c\u3002\u867d\u7136\u6570\u636e\u4fee\u6539\u8282\u70b9\u53ef\u80fd\u6d88\u8017\u76f8\u5f53\u591a\u7684\u8fd0\u884c\u65f6\u95f4\uff08\u672c\u4f8b\u4e2d\u5360\u4e86\u7edd\u5927\u90e8\u5206\uff09\uff0c\u4f46\u89c4\u5212\u5668\u76ee\u524d\u5e76\u672a\u5c06\u8fd9\u90e8\u5206\u5de5\u4f5c\u8ba1\u5165\u4ee3\u4ef7\u4f30\u7b97\u3002\u8fd9\u662f\u56e0\u4e3a\u4efb\u4f55\u6b63\u786e\u67e5\u8be2\u8ba1\u5212\u9700\u8981\u5b8c\u6210\u7684\u8fd9\u90e8\u5206\u5de5\u4f5c\u90fd\u76f8\u540c\uff0c\u56e0\u6b64\u4e0d\u4f1a\u5f71\u54cd\u89c4\u5212\u51b3\u7b56\u3002", "UPDATE\u3001DELETE \u6216 MERGE \u4f5c\u7528\u4e8e\u7ee7\u627f\u5c42\u7ea7\u65f6\uff0c\u8f93\u51fa\u53ef\u80fd\u5982\u4e0b\uff1a", "\u5f52\u5e76\u8fde\u63a5\u7684\u6d4b\u91cf\u7ed3\u679c\u4e5f\u53ef\u80fd\u4ea7\u751f\u8bef\u5bfc\u3002\u82e5\u4e00\u4fa7\u8f93\u5165\u5df2\u8017\u5c3d\uff0c\u53e6\u4e00\u4fa7\u7684\u4e0b\u4e00\u4e2a\u952e\u503c\u53c8\u5927\u4e8e\u5df2\u8017\u5c3d\u8f93\u5165\u7684\u6700\u540e\u4e00\u4e2a\u952e\u503c\uff0c\u5c31\u4e0d\u4f1a\u518d\u6709\u5339\u914d\uff0c\u56e0\u6b64\u4f1a\u505c\u6b62\u8bfb\u53d6\u53e6\u4e00\u4fa7\u3002\u8fd9\u6837\u4fbf\u672a\u8bfb\u53d6\u8be5\u5b50\u8282\u70b9\u7684\u5168\u90e8\u884c\uff0c\u7c7b\u4f3c LIMIT \u7684\u60c5\u51b5\u3002\u53e6\u5916\uff0c\u5916\u4fa7\uff08\u7b2c\u4e00\u4e2a\uff09\u5b50\u8282\u70b9\u6709\u91cd\u590d\u952e\u503c\u65f6\uff0c\u5185\u4fa7\uff08\u7b2c\u4e8c\u4e2a\uff09\u5b50\u8282\u70b9\u4f1a\u56de\u9000\u5e76\u91cd\u65b0\u626b\u63cf\u5339\u914d\u8be5\u952e\u503c\u7684\u884c\u3002EXPLAIN ANALYZE \u4f1a\u5c06\u5185\u4fa7\u91cd\u590d\u8f93\u51fa\u7684\u884c\u8ba1\u4f5c\u989d\u5916\u7684\u771f\u5b9e\u884c\u3002\u56e0\u6b64\u5916\u4fa7\u91cd\u590d\u503c\u5f88\u591a\u65f6\uff0c\u5185\u4fa7\u8ba1\u5212\u8282\u70b9\u62a5\u544a\u7684\u5b9e\u9645\u884c\u6570\u53ef\u80fd\u663e\u8457\u8d85\u8fc7\u5185\u4fa7\u5173\u7cfb\u4e2d\u7684\u5b9e\u9645\u884c\u6570\u3002", "\u4e0e\u975e\u5e76\u884c\u8ba1\u5212\u4e00\u6837\uff0c\u9a71\u52a8\u8868\u53ef\u4ee5\u901a\u8fc7\u5d4c\u5957\u5faa\u73af\u3001\u54c8\u5e0c\u8fde\u63a5\u6216\u5f52\u5e76\u8fde\u63a5\u4e0e\u4e00\u4e2a\u6216\u591a\u4e2a\u5176\u4ed6\u8868\u8fde\u63a5\u3002\u8fde\u63a5\u7684\u5185\u4fa7\u53ef\u4ee5\u662f\u89c4\u5212\u5668\u652f\u6301\u7684\u4efb\u4f55\u7c7b\u578b\u7684\u975e\u5e76\u884c\u8ba1\u5212\uff0c\u53ea\u8981\u5b83\u80fd\u591f\u5b89\u5168\u5730\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u4e2d\u8fd0\u884c\u3002\u6839\u636e\u8fde\u63a5\u7c7b\u578b\uff0c\u5185\u4fa7\u4e5f\u53ef\u4ee5\u662f\u5e76\u884c\u8ba1\u5212\u3002", "\u5728 \u5f52\u5e76\u8fde\u63a5 \u4e2d\uff0c\u5185\u4fa7\u59cb\u7ec8\u662f\u975e\u5e76\u884c\u8ba1\u5212\uff0c\u56e0\u6b64\u4f1a\u88ab\u5b8c\u6574\u6267\u884c\u3002\u8fd9\u53ef\u80fd\u6548\u7387\u4e0d\u9ad8\uff0c\u5c24\u5176\u662f\u5728\u5fc5\u987b\u6267\u884c\u6392\u5e8f\u65f6\uff0c\u56e0\u4e3a\u5de5\u4f5c\u91cf\u548c\u7ed3\u679c\u6570\u636e\u4f1a\u5728\u6bcf\u4e2a\u534f\u4f5c\u8fdb\u7a0b\u4e2d\u91cd\u590d\u3002"]}, {"title": "\u672c\u7248\u624b\u518c\u4e2d\u7684\u793a\u4f8b", "blocks": [{"code": "EXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=198.11..268.19 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..656.28 rows=101 width=244)\n         Filter: (unique1 < 100)\n   ->  Sort  (cost=197.83..200.33 rows=1000 width=244)\n         Sort Key: t2.unique2\n         ->  Seq Scan on onek t2  (cost=0.00..148.00 rows=1000 width=244)", "source": {"url": "/docs/15/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 15.19 \u00b7 using-explain", "sha256": "d1f509457c647da453d2575c772d91022a0f115dd84f9a3b20f5ff25a243648f"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 15.19 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u53e6\u4e00\u79cd\u53ef\u80fd\u7684\u8fde\u63a5\u65b9\u5f0f\u662f\u5f52\u5e76\u8fde\u63a5\uff0c\u5982\u4e0b\u6240\u793a\uff1a"]}, {"code": "SET enable_sort = off;\n\nEXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=0.56..292.65 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..656.28 rows=101 width=244)\n         Filter: (unique1 < 100)\n   ->  Index Scan using onek_unique2 on onek t2  (cost=0.28..224.79 rows=1000 width=244)", "source": {"url": "/docs/15/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 15.19 \u00b7 using-explain", "sha256": "d1f509457c647da453d2575c772d91022a0f115dd84f9a3b20f5ff25a243648f"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 15.19 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u8003\u5bdf\u5176\u4ed6\u8ba1\u5212\u7684\u4e00\u79cd\u65b9\u6cd5\uff0c\u662f\u7528\u7b2c 20.7.1 \u8282\u4e2d\u7684\u542f\u7528/\u7981\u7528\u6807\u5fd7\uff0c\u5f3a\u5236\u89c4\u5212\u5668\u5ffd\u7565\u5b83\u539f\u672c\u8ba4\u4e3a\u6210\u672c\u6700\u4f4e\u7684\u7b56\u7565\u3002\uff08\u8fd9\u79cd\u65b9\u6cd5\u6bd4\u8f83\u7c97\u7cd9\uff0c\u4f46\u5f88\u6709\u7528\uff1b\u53e6\u89c1\u7b2c 14.3 \u8282\u3002\uff09\u4f8b\u5982\uff0c\u82e5\u4e0d\u786e\u4fe1\u4e0a\u4f8b\u5904\u7406 onek \u7684\u6700\u4f73\u65b9\u5f0f\u662f\u987a\u5e8f\u626b\u63cf\u52a0\u6392\u5e8f\uff0c\u53ef\u4ee5\u5c1d\u8bd5\uff1a"]}]}, {"title": "\u6267\u884c\u5668\u5b9e\u73b0\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u5bf9\u6ee1\u8db3 ((= outerKey innerKey) ...) \u5f62\u5f0f\u8fde\u63a5\u6761\u4ef6\u7684\u5185\u5916\u4fa7\u5143\u7ec4\u6267\u884c\u8fde\u63a5\u3002\u8fde\u63a5\u6761\u4ef6\u5217\u8868\u7531\u67e5\u8be2\u89c4\u5212\u5668\u63d0\u4f9b\uff0c\u53ef\u4ee5\u5305\u542b\u591a\u4e2a (= outerKey innerKey) \u6761\u4ef6\uff0c\u4ee5\u652f\u6301\u590d\u5408\u6392\u5e8f\u952e\u3002", "\u4e0d\u8fc7\uff0c\u67e5\u8be2\u6267\u884c\u5668\u9700\u8981\u5224\u65ad\u5916\u4fa7\u5143\u7ec4\u662f\u5426\u201c\u5927\u4e8e\uff0f\u5c0f\u4e8e\u201d\u5185\u4fa7\u5143\u7ec4\uff0c\u4ee5\u4fbf\u201c\u540c\u6b65\u201d\u4e24\u4e2a\u5173\u7cfb\u3002\u4f8b\u5982\uff0c\u8003\u8651\u4ee5\u4e0b\u5173\u7cfb\uff1a", "outer: (0 ^1 1 2 5 5 5 6 6 7) current tuple: 1 inner: (1 ^3 5 5 5 5 6) current tuple: 3", "\u4e3a\u7ee7\u7eed\u5f52\u5e76\u8fde\u63a5\uff0c\u6267\u884c\u5668\u9700\u8981\u626b\u63cf\u5185\u5916\u4fa7\u5173\u7cfb\uff0c\u76f4\u5230\u627e\u5230\u5339\u914d\u7684\u5143\u7ec4 5\u3002\u5b83\u9700\u8981\u77e5\u9053\u5f53\u524d\u5185\u4fa7\u5143\u7ec4 3\u201c\u5927\u4e8e\u201d\u5916\u4fa7\u5143\u7ec4 1\uff0c\u56e0\u6b64\u5e94\u5148\u626b\u63cf\u5916\u4fa7\u5173\u7cfb\u4ee5\u5bfb\u627e\u5339\u914d\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002", "\u56e0\u6b64\uff0c\u4e0d\u76f4\u63a5\u6267\u884c\u5f52\u5e76\u8fde\u63a5\u6761\u4ef6\uff0c\u800c\u662f\u5206\u522b\u6c42\u503c\u5de6\u53f3\u952e\u8868\u8fbe\u5f0f\uff0c\u518d\u9010\u5217\u6bd4\u8f83\uff08\u53c2\u89c1 MJCompare\uff09\u3002\u89c4\u5212\u5668\u63d0\u4f9b\u8db3\u591f\u7684\u8f93\u5165\u6392\u5e8f\u4fe1\u606f\uff0c\u8ba9\u6267\u884c\u5668\u786e\u5b9a\u6bd4\u8f83\u65b9\u6cd5\u3002\u53ef\u4ee5\u4f7f\u7528\u76f8\u5e94\u7684 B-tree \u6bd4\u8f83\u51fd\u6570\uff0c\u56e0\u4e3a Postgres \u7684\u6392\u5e8f\u8bed\u4e49\u4ec5\u7531 B-tree \u64cd\u4f5c\u7b26\u5bb6\u65cf\u5b9a\u4e49\u3002"]}, {"code": "case T_MergeJoin:\n\t\t\tpname = \"Merge\";\t/* \"Join\" gets added by jointype switch */\n\t\t\tsname = \"Merge Join\";\n\t\t\tbreak;", "title": "\u6838\u5fc3\u6e90\u7801\u4e2d\u7684 EXPLAIN \u6807\u8bc6"}], "strategies": [], "description": ["\u4f7f\u7528\u5f52\u5e76\u6761\u4ef6\u8fde\u63a5\u6709\u5e8f\u8f93\u5165\u6d41\u3002"], "localization": {"status": "complete", "sources": [{"url": "/docs/15/parallel-plans.html", "method": "same-major semantic node", "sha256": "f854eb236b7b7015acb3d4356b2199700ef6396672fbb271f4325b656c16e6c3", "language": "zh", "matched_nodes": ["#PARALLEL-PLANS/div[4]/div[2]/ul[0]/li[1]", "#PARALLEL-PLANS/div[4]/p[1]"]}], "language": "zh", "original_text": {"/versions/15/description/0": "Joins ordered input streams using merge clauses.", "/versions/15/facts/0/label": "Core node tag", "/versions/15/facts/1/label": "Structured EXPLAIN Node Type", "/versions/15/facts/2/label": "Inputs", "/versions/15/facts/2/value": "Ordered outer and inner child plans", "/versions/15/facts/3/label": "Output", "/versions/15/facts/3/value": "Joined tuples according to the selected join type", "/versions/15/facts/4/label": "Executor initializer", "/versions/15/facts/5/label": "Memory mechanism", "/versions/15/tables/0/title": "EXPLAIN labels in this source build", "/versions/15/related/1/label": "Using EXPLAIN", "/versions/15/related/2/label": "Parallel plans", "/versions/15/sections/0/title": "EXPLAIN names and attributes", "/versions/15/sections/1/title": "Memory and temporary storage", "/versions/15/sections/2/title": "Parallel execution and instrumentation", "/versions/15/sections/3/title": "Same-version manual discussion", "/versions/15/sections/4/title": "Examples from this manual build", "/versions/15/sections/5/title": "Executor implementation notes", "/versions/15/sections/6/title": "EXPLAIN identity in core source", "/versions/15/memory/description": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/15/sections/0/paragraphs/0": "Structured formats use the Node Type above. Text-format spellings can also include operation, strategy, join type, scan direction or aggregation-stage attributes.", "/versions/15/sections/0/paragraphs/1": "Text names recorded by this source: Merge.", "/versions/15/sections/0/paragraphs/2": "Parallel-aware and parallel-safe are different plan properties. A node running inside a parallel worker is not necessarily a parallel-aware node.", "/versions/15/sections/1/paragraphs/0": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/15/sections/2/paragraphs/0": "The source callbacks below can coordinate execution or collect worker instrumentation. Their presence is not a blanket claim that this node supports a shared parallel scan or shared state.", "/versions/15/sections/2/paragraphs/1": "Callbacks in this build: none extracted from this node implementation.", "/versions/15/sections/3/paragraphs/0": "Merge join requires its input data to be sorted on the join keys. In this plan the tenk1 data is sorted by using an index scan to visit the rows in the correct order, but a sequential scan and sort is preferred for onek , because there are many more rows to be visited in that table. (Sequential-scan-and-sort frequently beats an index scan for sorting many rows, because of the nonsequential disk access required by the index scan.)", "/versions/15/sections/3/paragraphs/1": "As seen in this example, when the query is an INSERT , UPDATE , DELETE , or MERGE command, the actual work of applying the table changes is done by a top-level Insert, Update, Delete, or Merge plan node. The plan nodes underneath this node perform the work of locating the old rows and/or computing the new data. So above, we see the same sort of bitmap table scan we've seen already, and its output is fed to an Update node that stores the updated rows. It's worth noting that although the data-modifying node can take a considerable amount of run time (here, it's consuming the lion's share of the time), the planner does not currently add anything to the cost estimates to account for that work. That's because the work to be done is the same for every correct query plan, so it doesn't affect planning decisions.", "/versions/15/sections/3/paragraphs/2": "When an UPDATE , DELETE , or MERGE command affects an inheritance hierarchy, the output might look like this:", "/versions/15/sections/3/paragraphs/3": "Merge joins also have measurement artifacts that can confuse the unwary. A merge join will stop reading one input if it's exhausted the other input and the next key value in the one input is greater than the last key value of the other input; in such a case there can be no more matches and so no need to scan the rest of the first input. This results in not reading all of one child, with results like those mentioned for LIMIT . Also, if the outer (first) child contains rows with duplicate key values, the inner (second) child is backed up and rescanned for the portion of its rows matching that key value. EXPLAIN ANALYZE counts these repeated emissions of the same inner rows as if they were real additional rows. When there are many outer duplicates, the reported actual row count for the inner child plan node can be significantly larger than the number of rows that are actually in the inner relation.", "/versions/15/sections/3/paragraphs/4": "Just as in a non-parallel plan, the driving table may be joined to one or more other tables using a nested loop, hash join, or merge join. The inner side of the join may be any kind of non-parallel plan that is otherwise supported by the planner provided that it is safe to run within a parallel worker. Depending on the join type, the inner side may also be a parallel plan.", "/versions/15/sections/3/paragraphs/5": "In a merge join , the inner side is always a non-parallel plan and therefore executed in full. This may be inefficient, especially if a sort must be performed, because the work and resulting data are duplicated in every cooperating process.", "/versions/15/sections/5/paragraphs/0": "Merge-join is done by joining the inner and outer tuples satisfying join clauses of the form ((= outerKey innerKey) ...). The join clause list is provided by the query planner and may contain more than one (= outerKey innerKey) clause (for composite sort key).", "/versions/15/sections/5/paragraphs/1": "However, the query executor needs to know whether an outer tuple is \"greater/smaller\" than an inner tuple so that it can \"synchronize\" the two relations. For example, consider the following relations:", "/versions/15/sections/5/paragraphs/3": "To continue the merge-join, the executor needs to scan both inner and outer relations till the matching tuples 5. It needs to know that currently inner tuple 3 is \"greater\" than outer tuple 1 and therefore it should scan the outer relation first to find a matching tuple and so on.", "/versions/15/sections/5/paragraphs/4": "Therefore, rather than directly executing the merge join clauses, we evaluate the left and right key expressions separately and then compare the columns one at a time (see MJCompare). The planner passes us enough information about the sort ordering of the inputs to allow us to determine how to make the comparison. We may use the appropriate btree comparison function, since Postgres' only notion of ordering is specified by btree opfamilies.", "/versions/15/tables/0/columns/0/label": "Text-format label", "/versions/15/tables/0/columns/1/label": "Structured node identity", "/versions/15/sections/4/blocks/0/paragraphs/0": "Example copied from the PostgreSQL 15.19 manual; it was not executed for this collection.", "/versions/15/sections/4/blocks/0/paragraphs/1": "Another possible type of join is a merge join, illustrated here:", "/versions/15/sections/4/blocks/1/paragraphs/0": "Example copied from the PostgreSQL 15.19 manual; it was not executed for this collection.", "/versions/15/sections/4/blocks/1/paragraphs/1": "One way to look at variant plans is to force the planner to disregard whatever strategy it thought was the cheapest, using the enable/disable flags described in Section 20.7.1 . (This is a crude tool, but useful. See also Section 14.3 .) For example, if we're unconvinced that sequential-scan-and-sort is the best way to deal with table onek in the previous example, we could try"}, "fallback_fields": [], "source_language": "en", "original_snapshot_sha256": "b39a8ad2e9c5d13ded2697ef87d162dafd41b8d9f099ec146ef96188cbfd3dfa"}, "evidence_kind": "source and documentation", "explain_names": ["Merge"], "partial_modes": [], "comparison_data": {"node_tag": "T_MergeJoin", "strategies": [], "text_names": ["Merge"], "initializer": "ExecInitMergeJoin", "partial_modes": [], "memory_mechanism": "unclassified", "parallel_callbacks": []}, "comparison_hash": "b17771ee4d48585afbaba91552e5eb00f05a4b6784aa491387217937a4a30511", "explain_prefixes": ["Parallel", "Async"], "runtime_verified": false, "source_inventory": {"explain": "src/backend/commands/explain.c", "executor": "src/backend/executor/execProcnode.c", "implementation": "src/backend/executor/nodeMergejoin.c"}, "parallel_callbacks": []}, "16": {"facts": [{"label": "\u6838\u5fc3\u8282\u70b9\u6807\u7b7e", "value": "T_MergeJoin"}, {"label": "\u7ed3\u6784\u5316 EXPLAIN \u8282\u70b9\u7c7b\u578b", "value": "Merge Join"}, {"label": "\u8f93\u5165", "value": "\u6709\u5e8f\u7684\u5916\u4fa7\u548c\u5185\u4fa7\u5b50\u8ba1\u5212"}, {"label": "\u8f93\u51fa", "value": "\u6309\u6240\u9009\u8fde\u63a5\u7c7b\u578b\u751f\u6210\u7684\u8fde\u63a5\u5143\u7ec4"}, {"label": "\u6267\u884c\u5668\u521d\u59cb\u5316\u51fd\u6570", "value": "ExecInitMergeJoin"}, {"label": "\u5185\u5b58\u673a\u5236", "value": "unclassified"}], "memory": {"evidence": [{"url": "https://ftp.postgresql.org/pub/source/v16.15/postgresql-16.15.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "8426514ac454d9e1feb343aff03cab36b27995ebbc313fccfb373f323716138e", "archive_sha256": "c1575341fa7bd40f5274ea465b34390f4dc64cdd0770af327005caaeb9f6b7ed"}], "mechanism": "unclassified", "description": "\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002", "source_notes": []}, "tables": [{"key": "explain-labels", "rows": [{"label": "Merge", "identity": "Merge Join"}], "title": "\u672c\u6784\u5efa\u4e2d\u7684 EXPLAIN \u6807\u7b7e", "columns": [{"key": "label", "label": "\u6587\u672c\u683c\u5f0f\u6807\u7b7e"}, {"key": "identity", "label": "\u7ed3\u6784\u5316\u8282\u70b9\u6807\u8bc6"}]}], "related": [{"url": "/wiki/sql/explain/?v=16", "label": "EXPLAIN"}, {"url": "/docs/16/using-explain.html", "label": "\u4f7f\u7528 EXPLAIN"}, {"url": "/docs/16/parallel-plans.html", "label": "\u5e76\u884c\u8ba1\u5212"}, {"url": "/wiki/guc/enable_mergejoin/?v=16", "label": "enable_mergejoin"}], "release": {"ref": "PostgreSQL 16.15 source archive", "label": "16.15", "major": "16", "channel": "stable", "revision": "c1575341fa7bd40f5274ea465b34390f4dc64cdd0770af327005caaeb9f6b7ed", "source_url": "https://ftp.postgresql.org/pub/source/v16.15/postgresql-16.15.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "https://ftp.postgresql.org/pub/source/v16.15/postgresql-16.15.tar.bz2", "line": 1250, "path": "src/backend/commands/explain.c", "label": "src/backend/commands/explain.c:1250", "sha256": "8e017f0116dbea471339b40c37a667cc9f95039e7e0329c783e5e8ce194de7e1", "archive_sha256": "c1575341fa7bd40f5274ea465b34390f4dc64cdd0770af327005caaeb9f6b7ed"}, {"url": "https://ftp.postgresql.org/pub/source/v16.15/postgresql-16.15.tar.bz2", "line": 302, "path": "src/backend/executor/execProcnode.c", "label": "src/backend/executor/execProcnode.c:302", "sha256": "e48c08e555f8cb4e4bb43df516c4b8906ce9bc374b2a745d98a1fc8c22cc5099", "archive_sha256": "c1575341fa7bd40f5274ea465b34390f4dc64cdd0770af327005caaeb9f6b7ed"}, {"url": "https://ftp.postgresql.org/pub/source/v16.15/postgresql-16.15.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "8426514ac454d9e1feb343aff03cab36b27995ebbc313fccfb373f323716138e", "archive_sha256": "c1575341fa7bd40f5274ea465b34390f4dc64cdd0770af327005caaeb9f6b7ed"}, {"url": "https://ftp.postgresql.org/pub/source/v16.15/postgresql-16.15.tar.bz2", "path": "src/include/nodes/plannodes.h", "label": "src/include/nodes/plannodes.h", "sha256": "97db47353db76326b874589a5ad0a04501cc74cd72e237e7bd956e7472c41f1f", "archive_sha256": "c1575341fa7bd40f5274ea465b34390f4dc64cdd0770af327005caaeb9f6b7ed"}, {"url": "https://pg.center/docs/16/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 16.15 \u00b7 using-explain", "sha256": "bd8b86e5281cf0e52ad6e0e4bb8b6ff6510dac61982b44f0c1dd07d54012db3c", "language": "en", "original_url": "/docs/16/using-explain.html#USING-EXPLAIN-BASICS"}, {"url": "https://pg.center/docs/16/using-explain.html#USING-EXPLAIN-ANALYZE", "path": "using-explain.html", "label": "PostgreSQL 16.15 \u00b7 using-explain", "sha256": "bd8b86e5281cf0e52ad6e0e4bb8b6ff6510dac61982b44f0c1dd07d54012db3c", "language": "en", "original_url": "/docs/16/using-explain.html#USING-EXPLAIN-ANALYZE"}, {"url": "https://pg.center/docs/16/using-explain.html#USING-EXPLAIN-CAVEATS", "path": "using-explain.html", "label": "PostgreSQL 16.15 \u00b7 using-explain", "sha256": "bd8b86e5281cf0e52ad6e0e4bb8b6ff6510dac61982b44f0c1dd07d54012db3c", "language": "en", "original_url": "/docs/16/using-explain.html#USING-EXPLAIN-CAVEATS"}, {"url": "https://pg.center/docs/16/parallel-plans.html#PARALLEL-JOINS", "path": "parallel-plans.html", "label": "PostgreSQL 16.15 \u00b7 parallel-plans", "sha256": "53d83f63f97381fe1e4c0cfe5ceb81d30c1542b03e35a144684afd8fb3b9686c", "language": "en", "original_url": "/docs/16/parallel-plans.html#PARALLEL-JOINS"}], "node_tag": "T_MergeJoin", "sections": [{"title": "EXPLAIN \u540d\u79f0\u4e0e\u5c5e\u6027", "paragraphs": ["\u7ed3\u6784\u5316\u683c\u5f0f\u4f7f\u7528\u4e0a\u8ff0 Node Type\u3002\u6587\u672c\u683c\u5f0f\u540d\u79f0\u8fd8\u53ef\u80fd\u5305\u542b\u64cd\u4f5c\u3001\u7b56\u7565\u3001\u8fde\u63a5\u7c7b\u578b\u3001\u626b\u63cf\u65b9\u5411\u6216\u805a\u5408\u9636\u6bb5\u5c5e\u6027\u3002", "\u6b64\u6e90\u7801\u8bb0\u5f55\u7684\u6587\u672c\u540d\u79f0\uff1aMerge.", "\u5e76\u884c\u611f\u77e5\u4e0e\u5e76\u884c\u5b89\u5168\u662f\u4e0d\u540c\u7684\u8ba1\u5212\u5c5e\u6027\u3002\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u5185\u8fd0\u884c\u7684\u8282\u70b9\u4e0d\u4e00\u5b9a\u662f\u5e76\u884c\u611f\u77e5\u8282\u70b9\u3002"]}, {"title": "\u5185\u5b58\u4e0e\u4e34\u65f6\u5b58\u50a8", "paragraphs": ["\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002"]}, {"title": "\u5e76\u884c\u6267\u884c\u4e0e\u8fd0\u884c\u4fe1\u606f\u91c7\u96c6", "paragraphs": ["\u4ee5\u4e0b\u6e90\u7801\u56de\u8c03\u53ef\u4ee5\u534f\u8c03\u6267\u884c\u6216\u6536\u96c6\u5de5\u4f5c\u8fdb\u7a0b\u7684\u6d4b\u91cf\u6570\u636e\u3002\u56de\u8c03\u5b58\u5728\u4e0d\u4ee3\u8868\u8be5\u8282\u70b9\u666e\u904d\u652f\u6301\u5171\u4eab\u5e76\u884c\u626b\u63cf\u6216\u5171\u4eab\u72b6\u6001\u3002", "\u6b64\u6784\u5efa\u7684\u56de\u8c03\uff1anone extracted from this node implementation."]}, {"title": "\u540c\u7248\u672c\u624b\u518c\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u8981\u6c42\u8f93\u5165\u6309\u8fde\u63a5\u952e\u6392\u5e8f\u3002\u6b64\u8ba1\u5212\u901a\u8fc7\u7d22\u5f15\u626b\u63cf\u6309\u987a\u5e8f\u8bfb\u53d6 tenk1\uff1b\u5bf9\u4e8e onek\uff0c\u5219\u503e\u5411\u4e8e\u987a\u5e8f\u626b\u63cf\u540e\u6392\u5e8f\uff0c\u56e0\u4e3a\u8be5\u8868\u8981\u8bbf\u95ee\u7684\u884c\u66f4\u591a\u3002\uff08\u5bf9\u5927\u91cf\u884c\u6392\u5e8f\u65f6\uff0c\u987a\u5e8f\u626b\u63cf\u52a0\u6392\u5e8f\u5e38\u5e38\u4f18\u4e8e\u7d22\u5f15\u626b\u63cf\uff0c\u56e0\u4e3a\u540e\u8005\u9700\u8981\u975e\u987a\u5e8f\u78c1\u76d8\u8bbf\u95ee\u3002\uff09", "\u5982\u672c\u4f8b\u6240\u793a\uff0c\u67e5\u8be2\u4e3a INSERT\u3001UPDATE\u3001DELETE \u6216 MERGE \u547d\u4ee4\u65f6\uff0c\u5b9e\u9645\u5e94\u7528\u8868\u53d8\u66f4\u7684\u5de5\u4f5c\u7531\u9876\u5c42 Insert\u3001Update\u3001Delete \u6216 Merge \u8ba1\u5212\u8282\u70b9\u5b8c\u6210\u3002\u5176\u4e0b\u7684\u8ba1\u5212\u8282\u70b9\u8d1f\u8d23\u5b9a\u4f4d\u65e7\u884c\u548c\uff0f\u6216\u8ba1\u7b97\u65b0\u6570\u636e\u3002\u56e0\u6b64\uff0c\u4e0a\u4f8b\u4ecd\u91c7\u7528\u524d\u9762\u89c1\u8fc7\u7684\u4f4d\u56fe\u8868\u626b\u63cf\uff0c\u5176\u8f93\u51fa\u4f20\u7ed9 Update \u8282\u70b9\uff0c\u7531\u540e\u8005\u5b58\u50a8\u66f4\u65b0\u540e\u7684\u884c\u3002\u867d\u7136\u6570\u636e\u4fee\u6539\u8282\u70b9\u53ef\u80fd\u6d88\u8017\u76f8\u5f53\u591a\u7684\u8fd0\u884c\u65f6\u95f4\uff08\u672c\u4f8b\u4e2d\u5360\u4e86\u7edd\u5927\u90e8\u5206\uff09\uff0c\u4f46\u89c4\u5212\u5668\u76ee\u524d\u5e76\u672a\u5c06\u8fd9\u90e8\u5206\u5de5\u4f5c\u8ba1\u5165\u4ee3\u4ef7\u4f30\u7b97\u3002\u8fd9\u662f\u56e0\u4e3a\u4efb\u4f55\u6b63\u786e\u67e5\u8be2\u8ba1\u5212\u9700\u8981\u5b8c\u6210\u7684\u8fd9\u90e8\u5206\u5de5\u4f5c\u90fd\u76f8\u540c\uff0c\u56e0\u6b64\u4e0d\u4f1a\u5f71\u54cd\u89c4\u5212\u51b3\u7b56\u3002", "UPDATE\u3001DELETE \u6216 MERGE \u4f5c\u7528\u4e8e\u7ee7\u627f\u5c42\u7ea7\u65f6\uff0c\u8f93\u51fa\u53ef\u80fd\u5982\u4e0b\uff1a", "\u5f52\u5e76\u8fde\u63a5\u7684\u6d4b\u91cf\u7ed3\u679c\u4e5f\u53ef\u80fd\u4ea7\u751f\u8bef\u5bfc\u3002\u82e5\u4e00\u4fa7\u8f93\u5165\u5df2\u8017\u5c3d\uff0c\u53e6\u4e00\u4fa7\u7684\u4e0b\u4e00\u4e2a\u952e\u503c\u53c8\u5927\u4e8e\u5df2\u8017\u5c3d\u8f93\u5165\u7684\u6700\u540e\u4e00\u4e2a\u952e\u503c\uff0c\u5c31\u4e0d\u4f1a\u518d\u6709\u5339\u914d\uff0c\u56e0\u6b64\u4f1a\u505c\u6b62\u8bfb\u53d6\u53e6\u4e00\u4fa7\u3002\u8fd9\u6837\u4fbf\u672a\u8bfb\u53d6\u8be5\u5b50\u8282\u70b9\u7684\u5168\u90e8\u884c\uff0c\u7c7b\u4f3c LIMIT \u7684\u60c5\u51b5\u3002\u53e6\u5916\uff0c\u5916\u4fa7\uff08\u7b2c\u4e00\u4e2a\uff09\u5b50\u8282\u70b9\u6709\u91cd\u590d\u952e\u503c\u65f6\uff0c\u5185\u4fa7\uff08\u7b2c\u4e8c\u4e2a\uff09\u5b50\u8282\u70b9\u4f1a\u56de\u9000\u5e76\u91cd\u65b0\u626b\u63cf\u5339\u914d\u8be5\u952e\u503c\u7684\u884c\u3002EXPLAIN ANALYZE \u4f1a\u5c06\u5185\u4fa7\u91cd\u590d\u8f93\u51fa\u7684\u884c\u8ba1\u4f5c\u989d\u5916\u7684\u771f\u5b9e\u884c\u3002\u56e0\u6b64\u5916\u4fa7\u91cd\u590d\u503c\u5f88\u591a\u65f6\uff0c\u5185\u4fa7\u8ba1\u5212\u8282\u70b9\u62a5\u544a\u7684\u5b9e\u9645\u884c\u6570\u53ef\u80fd\u663e\u8457\u8d85\u8fc7\u5185\u4fa7\u5173\u7cfb\u4e2d\u7684\u5b9e\u9645\u884c\u6570\u3002", "\u4e0e\u975e\u5e76\u884c\u8ba1\u5212\u4e00\u6837\uff0c\u9a71\u52a8\u8868\u53ef\u4ee5\u901a\u8fc7\u5d4c\u5957\u5faa\u73af\u3001\u54c8\u5e0c\u8fde\u63a5\u6216\u5f52\u5e76\u8fde\u63a5\u4e0e\u4e00\u4e2a\u6216\u591a\u4e2a\u5176\u4ed6\u8868\u8fde\u63a5\u3002\u8fde\u63a5\u7684\u5185\u4fa7\u53ef\u4ee5\u662f\u89c4\u5212\u5668\u652f\u6301\u7684\u4efb\u4f55\u7c7b\u578b\u7684\u975e\u5e76\u884c\u8ba1\u5212\uff0c\u53ea\u8981\u5b83\u80fd\u591f\u5b89\u5168\u5730\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u4e2d\u8fd0\u884c\u3002\u6839\u636e\u8fde\u63a5\u7c7b\u578b\uff0c\u5185\u4fa7\u4e5f\u53ef\u4ee5\u662f\u5e76\u884c\u8ba1\u5212\u3002", "\u5728 \u5f52\u5e76\u8fde\u63a5 \u4e2d\uff0c\u5185\u4fa7\u59cb\u7ec8\u662f\u975e\u5e76\u884c\u8ba1\u5212\uff0c\u56e0\u6b64\u4f1a\u88ab\u5b8c\u6574\u6267\u884c\u3002\u8fd9\u53ef\u80fd\u6548\u7387\u4e0d\u9ad8\uff0c\u5c24\u5176\u662f\u5728\u5fc5\u987b\u6267\u884c\u6392\u5e8f\u65f6\uff0c\u56e0\u4e3a\u5de5\u4f5c\u91cf\u548c\u7ed3\u679c\u6570\u636e\u4f1a\u5728\u6bcf\u4e2a\u534f\u4f5c\u8fdb\u7a0b\u4e2d\u91cd\u590d\u3002"]}, {"title": "\u672c\u7248\u624b\u518c\u4e2d\u7684\u793a\u4f8b", "blocks": [{"code": "EXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=198.11..268.19 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..656.28 rows=101 width=244)\n         Filter: (unique1 < 100)\n   ->  Sort  (cost=197.83..200.33 rows=1000 width=244)\n         Sort Key: t2.unique2\n         ->  Seq Scan on onek t2  (cost=0.00..148.00 rows=1000 width=244)", "source": {"url": "/docs/16/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 16.15 \u00b7 using-explain", "sha256": "bd8b86e5281cf0e52ad6e0e4bb8b6ff6510dac61982b44f0c1dd07d54012db3c"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 16.15 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u53e6\u4e00\u79cd\u53ef\u80fd\u7684\u8fde\u63a5\u65b9\u5f0f\u662f\u5f52\u5e76\u8fde\u63a5\uff0c\u5982\u4e0b\u6240\u793a\uff1a"]}, {"code": "SET enable_sort = off;\n\nEXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=0.56..292.65 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..656.28 rows=101 width=244)\n         Filter: (unique1 < 100)\n   ->  Index Scan using onek_unique2 on onek t2  (cost=0.28..224.79 rows=1000 width=244)", "source": {"url": "/docs/16/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 16.15 \u00b7 using-explain", "sha256": "bd8b86e5281cf0e52ad6e0e4bb8b6ff6510dac61982b44f0c1dd07d54012db3c"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 16.15 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u8003\u5bdf\u5176\u4ed6\u8ba1\u5212\u7684\u4e00\u79cd\u65b9\u6cd5\uff0c\u662f\u7528\u7b2c 20.7.1 \u8282\u4e2d\u7684\u542f\u7528/\u7981\u7528\u6807\u5fd7\uff0c\u5f3a\u5236\u89c4\u5212\u5668\u5ffd\u7565\u5b83\u539f\u672c\u8ba4\u4e3a\u6210\u672c\u6700\u4f4e\u7684\u7b56\u7565\u3002\uff08\u8fd9\u79cd\u65b9\u6cd5\u6bd4\u8f83\u7c97\u7cd9\uff0c\u4f46\u5f88\u6709\u7528\uff1b\u53e6\u89c1\u7b2c 14.3 \u8282\u3002\uff09\u4f8b\u5982\uff0c\u82e5\u4e0d\u786e\u4fe1\u4e0a\u4f8b\u5904\u7406 onek \u7684\u6700\u4f73\u65b9\u5f0f\u662f\u987a\u5e8f\u626b\u63cf\u52a0\u6392\u5e8f\uff0c\u53ef\u4ee5\u5c1d\u8bd5\uff1a"]}]}, {"title": "\u6267\u884c\u5668\u5b9e\u73b0\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u5bf9\u6ee1\u8db3 ((= outerKey innerKey) ...) \u5f62\u5f0f\u8fde\u63a5\u6761\u4ef6\u7684\u5185\u5916\u4fa7\u5143\u7ec4\u6267\u884c\u8fde\u63a5\u3002\u8fde\u63a5\u6761\u4ef6\u5217\u8868\u7531\u67e5\u8be2\u89c4\u5212\u5668\u63d0\u4f9b\uff0c\u53ef\u4ee5\u5305\u542b\u591a\u4e2a (= outerKey innerKey) \u6761\u4ef6\uff0c\u4ee5\u652f\u6301\u590d\u5408\u6392\u5e8f\u952e\u3002", "\u4e0d\u8fc7\uff0c\u67e5\u8be2\u6267\u884c\u5668\u9700\u8981\u5224\u65ad\u5916\u4fa7\u5143\u7ec4\u662f\u5426\u201c\u5927\u4e8e\uff0f\u5c0f\u4e8e\u201d\u5185\u4fa7\u5143\u7ec4\uff0c\u4ee5\u4fbf\u201c\u540c\u6b65\u201d\u4e24\u4e2a\u5173\u7cfb\u3002\u4f8b\u5982\uff0c\u8003\u8651\u4ee5\u4e0b\u5173\u7cfb\uff1a", "outer: (0 ^1 1 2 5 5 5 6 6 7) current tuple: 1 inner: (1 ^3 5 5 5 5 6) current tuple: 3", "\u4e3a\u7ee7\u7eed\u5f52\u5e76\u8fde\u63a5\uff0c\u6267\u884c\u5668\u9700\u8981\u626b\u63cf\u5185\u5916\u4fa7\u5173\u7cfb\uff0c\u76f4\u5230\u627e\u5230\u5339\u914d\u7684\u5143\u7ec4 5\u3002\u5b83\u9700\u8981\u77e5\u9053\u5f53\u524d\u5185\u4fa7\u5143\u7ec4 3\u201c\u5927\u4e8e\u201d\u5916\u4fa7\u5143\u7ec4 1\uff0c\u56e0\u6b64\u5e94\u5148\u626b\u63cf\u5916\u4fa7\u5173\u7cfb\u4ee5\u5bfb\u627e\u5339\u914d\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002", "\u56e0\u6b64\uff0c\u4e0d\u76f4\u63a5\u6267\u884c\u5f52\u5e76\u8fde\u63a5\u6761\u4ef6\uff0c\u800c\u662f\u5206\u522b\u6c42\u503c\u5de6\u53f3\u952e\u8868\u8fbe\u5f0f\uff0c\u518d\u9010\u5217\u6bd4\u8f83\uff08\u53c2\u89c1 MJCompare\uff09\u3002\u89c4\u5212\u5668\u63d0\u4f9b\u8db3\u591f\u7684\u8f93\u5165\u6392\u5e8f\u4fe1\u606f\uff0c\u8ba9\u6267\u884c\u5668\u786e\u5b9a\u6bd4\u8f83\u65b9\u6cd5\u3002\u53ef\u4ee5\u4f7f\u7528\u76f8\u5e94\u7684 B-tree \u6bd4\u8f83\u51fd\u6570\uff0c\u56e0\u4e3a Postgres \u7684\u6392\u5e8f\u8bed\u4e49\u4ec5\u7531 B-tree \u64cd\u4f5c\u7b26\u5bb6\u65cf\u5b9a\u4e49\u3002"]}, {"code": "case T_MergeJoin:\n\t\t\tpname = \"Merge\";\t/* \"Join\" gets added by jointype switch */\n\t\t\tsname = \"Merge Join\";\n\t\t\tbreak;", "title": "\u6838\u5fc3\u6e90\u7801\u4e2d\u7684 EXPLAIN \u6807\u8bc6"}], "strategies": [], "description": ["\u4f7f\u7528\u5f52\u5e76\u6761\u4ef6\u8fde\u63a5\u6709\u5e8f\u8f93\u5165\u6d41\u3002"], "localization": {"status": "complete", "sources": [{"url": "/docs/16/parallel-plans.html", "method": "same-major semantic node", "sha256": "ebdab5889ade652e62c92fd2e4361d8aa32ae8132faccfdcafab869292fc4392", "language": "zh", "matched_nodes": ["#PARALLEL-PLANS/div[4]/div[2]/ul[0]/li[1]", "#PARALLEL-PLANS/div[4]/p[1]"]}], "language": "zh", "original_text": {"/versions/16/description/0": "Joins ordered input streams using merge clauses.", "/versions/16/facts/0/label": "Core node tag", "/versions/16/facts/1/label": "Structured EXPLAIN Node Type", "/versions/16/facts/2/label": "Inputs", "/versions/16/facts/2/value": "Ordered outer and inner child plans", "/versions/16/facts/3/label": "Output", "/versions/16/facts/3/value": "Joined tuples according to the selected join type", "/versions/16/facts/4/label": "Executor initializer", "/versions/16/facts/5/label": "Memory mechanism", "/versions/16/tables/0/title": "EXPLAIN labels in this source build", "/versions/16/related/1/label": "Using EXPLAIN", "/versions/16/related/2/label": "Parallel plans", "/versions/16/sections/0/title": "EXPLAIN names and attributes", "/versions/16/sections/1/title": "Memory and temporary storage", "/versions/16/sections/2/title": "Parallel execution and instrumentation", "/versions/16/sections/3/title": "Same-version manual discussion", "/versions/16/sections/4/title": "Examples from this manual build", "/versions/16/sections/5/title": "Executor implementation notes", "/versions/16/sections/6/title": "EXPLAIN identity in core source", "/versions/16/memory/description": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/16/sections/0/paragraphs/0": "Structured formats use the Node Type above. Text-format spellings can also include operation, strategy, join type, scan direction or aggregation-stage attributes.", "/versions/16/sections/0/paragraphs/1": "Text names recorded by this source: Merge.", "/versions/16/sections/0/paragraphs/2": "Parallel-aware and parallel-safe are different plan properties. A node running inside a parallel worker is not necessarily a parallel-aware node.", "/versions/16/sections/1/paragraphs/0": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/16/sections/2/paragraphs/0": "The source callbacks below can coordinate execution or collect worker instrumentation. Their presence is not a blanket claim that this node supports a shared parallel scan or shared state.", "/versions/16/sections/2/paragraphs/1": "Callbacks in this build: none extracted from this node implementation.", "/versions/16/sections/3/paragraphs/0": "Merge join requires its input data to be sorted on the join keys. In this plan the tenk1 data is sorted by using an index scan to visit the rows in the correct order, but a sequential scan and sort is preferred for onek , because there are many more rows to be visited in that table. (Sequential-scan-and-sort frequently beats an index scan for sorting many rows, because of the nonsequential disk access required by the index scan.)", "/versions/16/sections/3/paragraphs/1": "As seen in this example, when the query is an INSERT , UPDATE , DELETE , or MERGE command, the actual work of applying the table changes is done by a top-level Insert, Update, Delete, or Merge plan node. The plan nodes underneath this node perform the work of locating the old rows and/or computing the new data. So above, we see the same sort of bitmap table scan we've seen already, and its output is fed to an Update node that stores the updated rows. It's worth noting that although the data-modifying node can take a considerable amount of run time (here, it's consuming the lion's share of the time), the planner does not currently add anything to the cost estimates to account for that work. That's because the work to be done is the same for every correct query plan, so it doesn't affect planning decisions.", "/versions/16/sections/3/paragraphs/2": "When an UPDATE , DELETE , or MERGE command affects an inheritance hierarchy, the output might look like this:", "/versions/16/sections/3/paragraphs/3": "Merge joins also have measurement artifacts that can confuse the unwary. A merge join will stop reading one input if it's exhausted the other input and the next key value in the one input is greater than the last key value of the other input; in such a case there can be no more matches and so no need to scan the rest of the first input. This results in not reading all of one child, with results like those mentioned for LIMIT . Also, if the outer (first) child contains rows with duplicate key values, the inner (second) child is backed up and rescanned for the portion of its rows matching that key value. EXPLAIN ANALYZE counts these repeated emissions of the same inner rows as if they were real additional rows. When there are many outer duplicates, the reported actual row count for the inner child plan node can be significantly larger than the number of rows that are actually in the inner relation.", "/versions/16/sections/3/paragraphs/4": "Just as in a non-parallel plan, the driving table may be joined to one or more other tables using a nested loop, hash join, or merge join. The inner side of the join may be any kind of non-parallel plan that is otherwise supported by the planner provided that it is safe to run within a parallel worker. Depending on the join type, the inner side may also be a parallel plan.", "/versions/16/sections/3/paragraphs/5": "In a merge join , the inner side is always a non-parallel plan and therefore executed in full. This may be inefficient, especially if a sort must be performed, because the work and resulting data are duplicated in every cooperating process.", "/versions/16/sections/5/paragraphs/0": "Merge-join is done by joining the inner and outer tuples satisfying join clauses of the form ((= outerKey innerKey) ...). The join clause list is provided by the query planner and may contain more than one (= outerKey innerKey) clause (for composite sort key).", "/versions/16/sections/5/paragraphs/1": "However, the query executor needs to know whether an outer tuple is \"greater/smaller\" than an inner tuple so that it can \"synchronize\" the two relations. For example, consider the following relations:", "/versions/16/sections/5/paragraphs/3": "To continue the merge-join, the executor needs to scan both inner and outer relations till the matching tuples 5. It needs to know that currently inner tuple 3 is \"greater\" than outer tuple 1 and therefore it should scan the outer relation first to find a matching tuple and so on.", "/versions/16/sections/5/paragraphs/4": "Therefore, rather than directly executing the merge join clauses, we evaluate the left and right key expressions separately and then compare the columns one at a time (see MJCompare). The planner passes us enough information about the sort ordering of the inputs to allow us to determine how to make the comparison. We may use the appropriate btree comparison function, since Postgres' only notion of ordering is specified by btree opfamilies.", "/versions/16/tables/0/columns/0/label": "Text-format label", "/versions/16/tables/0/columns/1/label": "Structured node identity", "/versions/16/sections/4/blocks/0/paragraphs/0": "Example copied from the PostgreSQL 16.15 manual; it was not executed for this collection.", "/versions/16/sections/4/blocks/0/paragraphs/1": "Another possible type of join is a merge join, illustrated here:", "/versions/16/sections/4/blocks/1/paragraphs/0": "Example copied from the PostgreSQL 16.15 manual; it was not executed for this collection.", "/versions/16/sections/4/blocks/1/paragraphs/1": "One way to look at variant plans is to force the planner to disregard whatever strategy it thought was the cheapest, using the enable/disable flags described in Section 20.7.1 . (This is a crude tool, but useful. See also Section 14.3 .) For example, if we're unconvinced that sequential-scan-and-sort is the best way to deal with table onek in the previous example, we could try"}, "fallback_fields": [], "source_language": "en", "original_snapshot_sha256": "a72f7298278556d9f3fe70be27c736a82cd58b288cfa5a401025d4bc88434519"}, "evidence_kind": "source and documentation", "explain_names": ["Merge"], "partial_modes": [], "comparison_data": {"node_tag": "T_MergeJoin", "strategies": [], "text_names": ["Merge"], "initializer": "ExecInitMergeJoin", "partial_modes": [], "memory_mechanism": "unclassified", "parallel_callbacks": []}, "comparison_hash": "b17771ee4d48585afbaba91552e5eb00f05a4b6784aa491387217937a4a30511", "explain_prefixes": ["Parallel", "Async"], "runtime_verified": false, "source_inventory": {"explain": "src/backend/commands/explain.c", "executor": "src/backend/executor/execProcnode.c", "implementation": "src/backend/executor/nodeMergejoin.c"}, "parallel_callbacks": []}, "17": {"facts": [{"label": "\u6838\u5fc3\u8282\u70b9\u6807\u7b7e", "value": "T_MergeJoin"}, {"label": "\u7ed3\u6784\u5316 EXPLAIN \u8282\u70b9\u7c7b\u578b", "value": "Merge Join"}, {"label": "\u8f93\u5165", "value": "\u6709\u5e8f\u7684\u5916\u4fa7\u548c\u5185\u4fa7\u5b50\u8ba1\u5212"}, {"label": "\u8f93\u51fa", "value": "\u6309\u6240\u9009\u8fde\u63a5\u7c7b\u578b\u751f\u6210\u7684\u8fde\u63a5\u5143\u7ec4"}, {"label": "\u6267\u884c\u5668\u521d\u59cb\u5316\u51fd\u6570", "value": "ExecInitMergeJoin"}, {"label": "\u5185\u5b58\u673a\u5236", "value": "unclassified"}], "memory": {"evidence": [{"url": "https://ftp.postgresql.org/pub/source/v17.11/postgresql-17.11.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "31a47888da5b9d6a99193a92808c6e6d3d04d8ec0af049b28a10888b73503bc0", "archive_sha256": "dd27f2b3c59e73ed14aa3324901242bf69a032a6347805f274e6260322d42979"}], "mechanism": "unclassified", "description": "\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002", "source_notes": []}, "tables": [{"key": "explain-labels", "rows": [{"label": "Merge", "identity": "Merge Join"}], "title": "\u672c\u6784\u5efa\u4e2d\u7684 EXPLAIN \u6807\u7b7e", "columns": [{"key": "label", "label": "\u6587\u672c\u683c\u5f0f\u6807\u7b7e"}, {"key": "identity", "label": "\u7ed3\u6784\u5316\u8282\u70b9\u6807\u8bc6"}]}], "related": [{"url": "/wiki/sql/explain/?v=17", "label": "EXPLAIN"}, {"url": "/docs/17/using-explain.html", "label": "\u4f7f\u7528 EXPLAIN"}, {"url": "/docs/17/parallel-plans.html", "label": "\u5e76\u884c\u8ba1\u5212"}, {"url": "/wiki/guc/enable_mergejoin/?v=17", "label": "enable_mergejoin"}], "release": {"ref": "PostgreSQL 17.11 source archive", "label": "17.11", "major": "17", "channel": "stable", "revision": "dd27f2b3c59e73ed14aa3324901242bf69a032a6347805f274e6260322d42979", "source_url": "https://ftp.postgresql.org/pub/source/v17.11/postgresql-17.11.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "https://ftp.postgresql.org/pub/source/v17.11/postgresql-17.11.tar.bz2", "line": 1439, "path": "src/backend/commands/explain.c", "label": "src/backend/commands/explain.c:1439", "sha256": "741251b1a3b6d269a52a673d42eb63b02e13a5872db7b359b137086ab21b63c8", "archive_sha256": "dd27f2b3c59e73ed14aa3324901242bf69a032a6347805f274e6260322d42979"}, {"url": "https://ftp.postgresql.org/pub/source/v17.11/postgresql-17.11.tar.bz2", "line": 302, "path": "src/backend/executor/execProcnode.c", "label": "src/backend/executor/execProcnode.c:302", "sha256": "a77576e158b94cb01fa8c5174ba133004eabdd727660323f8afc66c8d2e757b8", "archive_sha256": "dd27f2b3c59e73ed14aa3324901242bf69a032a6347805f274e6260322d42979"}, {"url": "https://ftp.postgresql.org/pub/source/v17.11/postgresql-17.11.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "31a47888da5b9d6a99193a92808c6e6d3d04d8ec0af049b28a10888b73503bc0", "archive_sha256": "dd27f2b3c59e73ed14aa3324901242bf69a032a6347805f274e6260322d42979"}, {"url": "https://ftp.postgresql.org/pub/source/v17.11/postgresql-17.11.tar.bz2", "path": "src/include/nodes/plannodes.h", "label": "src/include/nodes/plannodes.h", "sha256": "d390dd69e2d3f5085beb42b33e46ff0676a2959b916a12b82118a7e545f8e562", "archive_sha256": "dd27f2b3c59e73ed14aa3324901242bf69a032a6347805f274e6260322d42979"}, {"url": "https://pg.center/docs/17/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 17.11 \u00b7 using-explain", "sha256": "8e3422c77496cc53bfc225ccadda3e82eb23c8c362b8eb95e7fb02cdb315ea78", "language": "en", "original_url": "/docs/17/using-explain.html#USING-EXPLAIN-BASICS"}, {"url": "https://pg.center/docs/17/using-explain.html#USING-EXPLAIN-ANALYZE", "path": "using-explain.html", "label": "PostgreSQL 17.11 \u00b7 using-explain", "sha256": "8e3422c77496cc53bfc225ccadda3e82eb23c8c362b8eb95e7fb02cdb315ea78", "language": "en", "original_url": "/docs/17/using-explain.html#USING-EXPLAIN-ANALYZE"}, {"url": "https://pg.center/docs/17/using-explain.html#USING-EXPLAIN-CAVEATS", "path": "using-explain.html", "label": "PostgreSQL 17.11 \u00b7 using-explain", "sha256": "8e3422c77496cc53bfc225ccadda3e82eb23c8c362b8eb95e7fb02cdb315ea78", "language": "en", "original_url": "/docs/17/using-explain.html#USING-EXPLAIN-CAVEATS"}], "node_tag": "T_MergeJoin", "sections": [{"title": "EXPLAIN \u540d\u79f0\u4e0e\u5c5e\u6027", "paragraphs": ["\u7ed3\u6784\u5316\u683c\u5f0f\u4f7f\u7528\u4e0a\u8ff0 Node Type\u3002\u6587\u672c\u683c\u5f0f\u540d\u79f0\u8fd8\u53ef\u80fd\u5305\u542b\u64cd\u4f5c\u3001\u7b56\u7565\u3001\u8fde\u63a5\u7c7b\u578b\u3001\u626b\u63cf\u65b9\u5411\u6216\u805a\u5408\u9636\u6bb5\u5c5e\u6027\u3002", "\u6b64\u6e90\u7801\u8bb0\u5f55\u7684\u6587\u672c\u540d\u79f0\uff1aMerge.", "\u5e76\u884c\u611f\u77e5\u4e0e\u5e76\u884c\u5b89\u5168\u662f\u4e0d\u540c\u7684\u8ba1\u5212\u5c5e\u6027\u3002\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u5185\u8fd0\u884c\u7684\u8282\u70b9\u4e0d\u4e00\u5b9a\u662f\u5e76\u884c\u611f\u77e5\u8282\u70b9\u3002"]}, {"title": "\u5185\u5b58\u4e0e\u4e34\u65f6\u5b58\u50a8", "paragraphs": ["\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002"]}, {"title": "\u5e76\u884c\u6267\u884c\u4e0e\u8fd0\u884c\u4fe1\u606f\u91c7\u96c6", "paragraphs": ["\u4ee5\u4e0b\u6e90\u7801\u56de\u8c03\u53ef\u4ee5\u534f\u8c03\u6267\u884c\u6216\u6536\u96c6\u5de5\u4f5c\u8fdb\u7a0b\u7684\u6d4b\u91cf\u6570\u636e\u3002\u56de\u8c03\u5b58\u5728\u4e0d\u4ee3\u8868\u8be5\u8282\u70b9\u666e\u904d\u652f\u6301\u5171\u4eab\u5e76\u884c\u626b\u63cf\u6216\u5171\u4eab\u72b6\u6001\u3002", "\u6b64\u6784\u5efa\u7684\u56de\u8c03\uff1anone extracted from this node implementation."]}, {"title": "\u540c\u7248\u672c\u624b\u518c\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u8981\u6c42\u8f93\u5165\u6570\u636e\u6309\u8fde\u63a5\u952e\u6392\u5e8f\u3002\u5728\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u4e24\u4e2a\u8f93\u5165\u90fd\u901a\u8fc7\u7d22\u5f15\u626b\u63cf\u6309\u6b63\u786e\u987a\u5e8f\u8bbf\u95ee\u884c\u800c\u5b8c\u6210\u6392\u5e8f\uff1b\u4e0d\u8fc7\u4e5f\u53ef\u4ee5\u91c7\u7528\u987a\u5e8f\u626b\u63cf\u518d\u6392\u5e8f\u7684\u65b9\u5f0f\u3002\uff08\u5bf9\u4e8e\u9700\u8981\u6392\u5e8f\u5f88\u591a\u884c\u7684\u60c5\u51b5\uff0c\u987a\u5e8f\u626b\u63cf\u52a0\u6392\u5e8f\u5f80\u5f80\u4f1a\u80dc\u8fc7\u7d22\u5f15\u626b\u63cf\uff0c\u56e0\u4e3a\u7d22\u5f15\u626b\u63cf\u9700\u8981\u975e\u987a\u5e8f\u78c1\u76d8\u8bbf\u95ee\u3002\uff09", "\u89c2\u5bdf\u5907\u9009\u8ba1\u5212\u7684\u4e00\u79cd\u65b9\u6cd5\uff0c\u662f\u5229\u7528 \u7b2c 19.7.1 \u8282 \u4e2d\u63cf\u8ff0\u7684\u542f\u7528/\u7981\u7528\u6807\u5fd7\uff0c\u5f3a\u8feb\u89c4\u5212\u5668\u5ffd\u7565\u5b83\u8ba4\u4e3a\u6700\u4fbf\u5b9c\u7684\u7b56\u7565\u3002\uff08\u8fd9\u662f\u4e2a\u7c97\u7cd9\u4f46\u6709\u7528\u7684\u5de5\u5177\u3002\u53e6\u89c1 \u7b2c 14.3 \u8282 \u3002\uff09\u4f8b\u5982\uff0c\u5982\u679c\u6211\u4eec\u5e76\u4e0d\u786e\u4fe1\u524d\u4e00\u4e2a\u793a\u4f8b\u4e2d\u5f52\u5e76\u8fde\u63a5\u771f\u7684\u662f\u6700\u4f73\u8fde\u63a5\u7c7b\u578b\uff0c\u53ef\u4ee5\u8bd5\u8bd5\uff1a", "\u8fd9\u8868\u660e\uff0c\u89c4\u5212\u5668\u8ba4\u4e3a\u5728\u8fd9\u4e2a\u573a\u666f\u4e0b\uff0c\u54c8\u5e0c\u8fde\u63a5\u7684\u4ee3\u4ef7\u51e0\u4e4e\u6bd4\u5f52\u5e76\u8fde\u63a5\u9ad8\u51fa 50%\u3002\u5f53\u7136\uff0c\u63a5\u4e0b\u6765\u7684\u95ee\u9898\u5c31\u662f\u5b83\u662f\u5426\u5224\u65ad\u6b63\u786e\u3002\u6211\u4eec\u53ef\u4ee5\u50cf \u4e0b\u6587 \u6240\u8ff0\uff0c\u4f7f\u7528 EXPLAIN ANALYZE \u6765\u7814\u7a76\u3002", "\u5982\u672c\u4f8b\u6240\u793a\uff0c\u67e5\u8be2\u4e3a INSERT\u3001UPDATE\u3001DELETE \u6216 MERGE \u547d\u4ee4\u65f6\uff0c\u5b9e\u9645\u5e94\u7528\u8868\u53d8\u66f4\u7684\u5de5\u4f5c\u7531\u9876\u5c42 Insert\u3001Update\u3001Delete \u6216 Merge \u8ba1\u5212\u8282\u70b9\u5b8c\u6210\u3002\u5176\u4e0b\u7684\u8ba1\u5212\u8282\u70b9\u8d1f\u8d23\u5b9a\u4f4d\u65e7\u884c\u548c\uff0f\u6216\u8ba1\u7b97\u65b0\u6570\u636e\u3002\u56e0\u6b64\uff0c\u4e0a\u4f8b\u4ecd\u91c7\u7528\u524d\u9762\u89c1\u8fc7\u7684\u4f4d\u56fe\u8868\u626b\u63cf\uff0c\u5176\u8f93\u51fa\u4f20\u7ed9 Update \u8282\u70b9\uff0c\u7531\u540e\u8005\u5b58\u50a8\u66f4\u65b0\u540e\u7684\u884c\u3002\u867d\u7136\u6570\u636e\u4fee\u6539\u8282\u70b9\u53ef\u80fd\u6d88\u8017\u76f8\u5f53\u591a\u7684\u8fd0\u884c\u65f6\u95f4\uff08\u672c\u4f8b\u4e2d\u5360\u4e86\u7edd\u5927\u90e8\u5206\uff09\uff0c\u4f46\u89c4\u5212\u5668\u76ee\u524d\u5e76\u672a\u5c06\u8fd9\u90e8\u5206\u5de5\u4f5c\u8ba1\u5165\u4ee3\u4ef7\u4f30\u7b97\u3002\u8fd9\u662f\u56e0\u4e3a\u4efb\u4f55\u6b63\u786e\u67e5\u8be2\u8ba1\u5212\u9700\u8981\u5b8c\u6210\u7684\u8fd9\u90e8\u5206\u5de5\u4f5c\u90fd\u76f8\u540c\uff0c\u56e0\u6b64\u4e0d\u4f1a\u5f71\u54cd\u89c4\u5212\u51b3\u7b56\u3002", "\u5f53 UPDATE \u3001 DELETE \u6216 MERGE \u547d\u4ee4\u5f71\u54cd\u5206\u533a\u8868\u6216\u7ee7\u627f\u5c42\u6b21\u65f6\uff0c\u8f93\u51fa\u53ef\u80fd\u50cf\u8fd9\u6837\uff1a", "\u5f52\u5e76\u8fde\u63a5\u7684\u6d4b\u91cf\u7ed3\u679c\u4e5f\u53ef\u80fd\u4ea7\u751f\u8bef\u5bfc\u3002\u82e5\u4e00\u4fa7\u8f93\u5165\u5df2\u8017\u5c3d\uff0c\u53e6\u4e00\u4fa7\u7684\u4e0b\u4e00\u4e2a\u952e\u503c\u53c8\u5927\u4e8e\u5df2\u8017\u5c3d\u8f93\u5165\u7684\u6700\u540e\u4e00\u4e2a\u952e\u503c\uff0c\u5c31\u4e0d\u4f1a\u518d\u6709\u5339\u914d\uff0c\u56e0\u6b64\u4f1a\u505c\u6b62\u8bfb\u53d6\u53e6\u4e00\u4fa7\u3002\u8fd9\u6837\u4fbf\u672a\u8bfb\u53d6\u8be5\u5b50\u8282\u70b9\u7684\u5168\u90e8\u884c\uff0c\u7c7b\u4f3c LIMIT \u7684\u60c5\u51b5\u3002\u53e6\u5916\uff0c\u5916\u4fa7\uff08\u7b2c\u4e00\u4e2a\uff09\u5b50\u8282\u70b9\u6709\u91cd\u590d\u952e\u503c\u65f6\uff0c\u5185\u4fa7\uff08\u7b2c\u4e8c\u4e2a\uff09\u5b50\u8282\u70b9\u4f1a\u56de\u9000\u5e76\u91cd\u65b0\u626b\u63cf\u5339\u914d\u8be5\u952e\u503c\u7684\u884c\u3002EXPLAIN ANALYZE \u4f1a\u5c06\u5185\u4fa7\u91cd\u590d\u8f93\u51fa\u7684\u884c\u8ba1\u4f5c\u989d\u5916\u7684\u771f\u5b9e\u884c\u3002\u56e0\u6b64\u5916\u4fa7\u91cd\u590d\u503c\u5f88\u591a\u65f6\uff0c\u5185\u4fa7\u8ba1\u5212\u8282\u70b9\u62a5\u544a\u7684\u5b9e\u9645\u884c\u6570\u53ef\u80fd\u663e\u8457\u8d85\u8fc7\u5185\u4fa7\u5173\u7cfb\u4e2d\u7684\u5b9e\u9645\u884c\u6570\u3002"]}, {"title": "\u672c\u7248\u624b\u518c\u4e2d\u7684\u793a\u4f8b", "blocks": [{"code": "EXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=0.56..233.49 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..643.28 rows=100 width=244)\n         Filter: (unique1 < 100)\n   ->  Index Scan using onek_unique2 on onek t2  (cost=0.28..166.28 rows=1000 width=244)", "source": {"url": "/docs/17/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 17.11 \u00b7 using-explain", "sha256": "8e3422c77496cc53bfc225ccadda3e82eb23c8c362b8eb95e7fb02cdb315ea78"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 17.11 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u53e6\u4e00\u79cd\u53ef\u80fd\u7684\u8fde\u63a5\u65b9\u5f0f\u662f\u5f52\u5e76\u8fde\u63a5\uff0c\u5982\u4e0b\u6240\u793a\uff1a"]}]}, {"title": "\u6267\u884c\u5668\u5b9e\u73b0\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u5bf9\u6ee1\u8db3 ((= outerKey innerKey) ...) \u5f62\u5f0f\u8fde\u63a5\u6761\u4ef6\u7684\u5185\u5916\u4fa7\u5143\u7ec4\u6267\u884c\u8fde\u63a5\u3002\u8fde\u63a5\u6761\u4ef6\u5217\u8868\u7531\u67e5\u8be2\u89c4\u5212\u5668\u63d0\u4f9b\uff0c\u53ef\u4ee5\u5305\u542b\u591a\u4e2a (= outerKey innerKey) \u6761\u4ef6\uff0c\u4ee5\u652f\u6301\u590d\u5408\u6392\u5e8f\u952e\u3002", "\u4e0d\u8fc7\uff0c\u67e5\u8be2\u6267\u884c\u5668\u9700\u8981\u5224\u65ad\u5916\u4fa7\u5143\u7ec4\u662f\u5426\u201c\u5927\u4e8e\uff0f\u5c0f\u4e8e\u201d\u5185\u4fa7\u5143\u7ec4\uff0c\u4ee5\u4fbf\u201c\u540c\u6b65\u201d\u4e24\u4e2a\u5173\u7cfb\u3002\u4f8b\u5982\uff0c\u8003\u8651\u4ee5\u4e0b\u5173\u7cfb\uff1a", "outer: (0 ^1 1 2 5 5 5 6 6 7) current tuple: 1 inner: (1 ^3 5 5 5 5 6) current tuple: 3", "\u4e3a\u7ee7\u7eed\u5f52\u5e76\u8fde\u63a5\uff0c\u6267\u884c\u5668\u9700\u8981\u626b\u63cf\u5185\u5916\u4fa7\u5173\u7cfb\uff0c\u76f4\u5230\u627e\u5230\u5339\u914d\u7684\u5143\u7ec4 5\u3002\u5b83\u9700\u8981\u77e5\u9053\u5f53\u524d\u5185\u4fa7\u5143\u7ec4 3\u201c\u5927\u4e8e\u201d\u5916\u4fa7\u5143\u7ec4 1\uff0c\u56e0\u6b64\u5e94\u5148\u626b\u63cf\u5916\u4fa7\u5173\u7cfb\u4ee5\u5bfb\u627e\u5339\u914d\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002", "\u56e0\u6b64\uff0c\u4e0d\u76f4\u63a5\u6267\u884c\u5f52\u5e76\u8fde\u63a5\u6761\u4ef6\uff0c\u800c\u662f\u5206\u522b\u6c42\u503c\u5de6\u53f3\u952e\u8868\u8fbe\u5f0f\uff0c\u518d\u9010\u5217\u6bd4\u8f83\uff08\u53c2\u89c1 MJCompare\uff09\u3002\u89c4\u5212\u5668\u63d0\u4f9b\u8db3\u591f\u7684\u8f93\u5165\u6392\u5e8f\u4fe1\u606f\uff0c\u8ba9\u6267\u884c\u5668\u786e\u5b9a\u6bd4\u8f83\u65b9\u6cd5\u3002\u53ef\u4ee5\u4f7f\u7528\u76f8\u5e94\u7684 B-tree \u6bd4\u8f83\u51fd\u6570\uff0c\u56e0\u4e3a Postgres \u7684\u6392\u5e8f\u8bed\u4e49\u4ec5\u7531 B-tree \u64cd\u4f5c\u7b26\u5bb6\u65cf\u5b9a\u4e49\u3002"]}, {"code": "case T_MergeJoin:\n\t\t\tpname = \"Merge\";\t/* \"Join\" gets added by jointype switch */\n\t\t\tsname = \"Merge Join\";\n\t\t\tbreak;", "title": "\u6838\u5fc3\u6e90\u7801\u4e2d\u7684 EXPLAIN \u6807\u8bc6"}], "strategies": [], "description": ["\u4f7f\u7528\u5f52\u5e76\u6761\u4ef6\u8fde\u63a5\u6709\u5e8f\u8f93\u5165\u6d41\u3002"], "localization": {"status": "complete", "sources": [{"url": "/docs/17/using-explain.html", "method": "same-major semantic node", "sha256": "610ae355c419b53a5e213a8c8e2eacbf34e4fa0ac8f6d27365071bc6d3c90278", "language": "zh", "matched_nodes": ["#USING-EXPLAIN/div[7]/p[51]", "#USING-EXPLAIN/div[7]/p[52]", "#USING-EXPLAIN/div[7]/p[54]", "#USING-EXPLAIN/div[8]/p[22]"]}], "language": "zh", "original_text": {"/versions/17/description/0": "Joins ordered input streams using merge clauses.", "/versions/17/facts/0/label": "Core node tag", "/versions/17/facts/1/label": "Structured EXPLAIN Node Type", "/versions/17/facts/2/label": "Inputs", "/versions/17/facts/2/value": "Ordered outer and inner child plans", "/versions/17/facts/3/label": "Output", "/versions/17/facts/3/value": "Joined tuples according to the selected join type", "/versions/17/facts/4/label": "Executor initializer", "/versions/17/facts/5/label": "Memory mechanism", "/versions/17/tables/0/title": "EXPLAIN labels in this source build", "/versions/17/related/1/label": "Using EXPLAIN", "/versions/17/related/2/label": "Parallel plans", "/versions/17/sections/0/title": "EXPLAIN names and attributes", "/versions/17/sections/1/title": "Memory and temporary storage", "/versions/17/sections/2/title": "Parallel execution and instrumentation", "/versions/17/sections/3/title": "Same-version manual discussion", "/versions/17/sections/4/title": "Examples from this manual build", "/versions/17/sections/5/title": "Executor implementation notes", "/versions/17/sections/6/title": "EXPLAIN identity in core source", "/versions/17/memory/description": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/17/sections/0/paragraphs/0": "Structured formats use the Node Type above. Text-format spellings can also include operation, strategy, join type, scan direction or aggregation-stage attributes.", "/versions/17/sections/0/paragraphs/1": "Text names recorded by this source: Merge.", "/versions/17/sections/0/paragraphs/2": "Parallel-aware and parallel-safe are different plan properties. A node running inside a parallel worker is not necessarily a parallel-aware node.", "/versions/17/sections/1/paragraphs/0": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/17/sections/2/paragraphs/0": "The source callbacks below can coordinate execution or collect worker instrumentation. Their presence is not a blanket claim that this node supports a shared parallel scan or shared state.", "/versions/17/sections/2/paragraphs/1": "Callbacks in this build: none extracted from this node implementation.", "/versions/17/sections/3/paragraphs/0": "Merge join requires its input data to be sorted on the join keys. In this example each input is sorted by using an index scan to visit the rows in the correct order; but a sequential scan and sort could also be used. (Sequential-scan-and-sort frequently beats an index scan for sorting many rows, because of the nonsequential disk access required by the index scan.)", "/versions/17/sections/3/paragraphs/1": "One way to look at variant plans is to force the planner to disregard whatever strategy it thought was the cheapest, using the enable/disable flags described in Section 19.7.1 . (This is a crude tool, but useful. See also Section 14.3 .) For example, if we're unconvinced that merge join is the best join type for the previous example, we could try", "/versions/17/sections/3/paragraphs/2": "which shows that the planner thinks that hash join would be nearly 50% more expensive than merge join for this case. Of course, the next question is whether it's right about that. We can investigate that using EXPLAIN ANALYZE , as discussed below .", "/versions/17/sections/3/paragraphs/3": "As seen in this example, when the query is an INSERT , UPDATE , DELETE , or MERGE command, the actual work of applying the table changes is done by a top-level Insert, Update, Delete, or Merge plan node. The plan nodes underneath this node perform the work of locating the old rows and/or computing the new data. So above, we see the same sort of bitmap table scan we've seen already, and its output is fed to an Update node that stores the updated rows. It's worth noting that although the data-modifying node can take a considerable amount of run time (here, it's consuming the lion's share of the time), the planner does not currently add anything to the cost estimates to account for that work. That's because the work to be done is the same for every correct query plan, so it doesn't affect planning decisions.", "/versions/17/sections/3/paragraphs/4": "When an UPDATE , DELETE , or MERGE command affects a partitioned table or inheritance hierarchy, the output might look like this:", "/versions/17/sections/3/paragraphs/5": "Merge joins also have measurement artifacts that can confuse the unwary. A merge join will stop reading one input if it's exhausted the other input and the next key value in the one input is greater than the last key value of the other input; in such a case there can be no more matches and so no need to scan the rest of the first input. This results in not reading all of one child, with results like those mentioned for LIMIT . Also, if the outer (first) child contains rows with duplicate key values, the inner (second) child is backed up and rescanned for the portion of its rows matching that key value. EXPLAIN ANALYZE counts these repeated emissions of the same inner rows as if they were real additional rows. When there are many outer duplicates, the reported actual row count for the inner child plan node can be significantly larger than the number of rows that are actually in the inner relation.", "/versions/17/sections/5/paragraphs/0": "Merge-join is done by joining the inner and outer tuples satisfying join clauses of the form ((= outerKey innerKey) ...). The join clause list is provided by the query planner and may contain more than one (= outerKey innerKey) clause (for composite sort key).", "/versions/17/sections/5/paragraphs/1": "However, the query executor needs to know whether an outer tuple is \"greater/smaller\" than an inner tuple so that it can \"synchronize\" the two relations. For example, consider the following relations:", "/versions/17/sections/5/paragraphs/3": "To continue the merge-join, the executor needs to scan both inner and outer relations till the matching tuples 5. It needs to know that currently inner tuple 3 is \"greater\" than outer tuple 1 and therefore it should scan the outer relation first to find a matching tuple and so on.", "/versions/17/sections/5/paragraphs/4": "Therefore, rather than directly executing the merge join clauses, we evaluate the left and right key expressions separately and then compare the columns one at a time (see MJCompare). The planner passes us enough information about the sort ordering of the inputs to allow us to determine how to make the comparison. We may use the appropriate btree comparison function, since Postgres' only notion of ordering is specified by btree opfamilies.", "/versions/17/tables/0/columns/0/label": "Text-format label", "/versions/17/tables/0/columns/1/label": "Structured node identity", "/versions/17/sections/4/blocks/0/paragraphs/0": "Example copied from the PostgreSQL 17.11 manual; it was not executed for this collection.", "/versions/17/sections/4/blocks/0/paragraphs/1": "Another possible type of join is a merge join, illustrated here:"}, "fallback_fields": [], "source_language": "en", "original_snapshot_sha256": "504903646a41f1a7dc462ffd78a876d08042586a8c62402c3a493765ff2d7376"}, "evidence_kind": "source and documentation", "explain_names": ["Merge"], "partial_modes": [], "comparison_data": {"node_tag": "T_MergeJoin", "strategies": [], "text_names": ["Merge"], "initializer": "ExecInitMergeJoin", "partial_modes": [], "memory_mechanism": "unclassified", "parallel_callbacks": []}, "comparison_hash": "b17771ee4d48585afbaba91552e5eb00f05a4b6784aa491387217937a4a30511", "explain_prefixes": ["Parallel", "Async"], "runtime_verified": false, "source_inventory": {"explain": "src/backend/commands/explain.c", "executor": "src/backend/executor/execProcnode.c", "implementation": "src/backend/executor/nodeMergejoin.c"}, "parallel_callbacks": []}, "18": {"facts": [{"label": "\u6838\u5fc3\u8282\u70b9\u6807\u7b7e", "value": "T_MergeJoin"}, {"label": "\u7ed3\u6784\u5316 EXPLAIN \u8282\u70b9\u7c7b\u578b", "value": "Merge Join"}, {"label": "\u8f93\u5165", "value": "\u6709\u5e8f\u7684\u5916\u4fa7\u548c\u5185\u4fa7\u5b50\u8ba1\u5212"}, {"label": "\u8f93\u51fa", "value": "\u6309\u6240\u9009\u8fde\u63a5\u7c7b\u578b\u751f\u6210\u7684\u8fde\u63a5\u5143\u7ec4"}, {"label": "\u6267\u884c\u5668\u521d\u59cb\u5316\u51fd\u6570", "value": "ExecInitMergeJoin"}, {"label": "\u5185\u5b58\u673a\u5236", "value": "unclassified"}], "memory": {"evidence": [{"url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "df6726b291493e06be7c43e5664bfb4251267eff66481eaf8e04969c39612b25", "archive_sha256": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}], "mechanism": "unclassified", "description": "\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002", "source_notes": []}, "tables": [{"key": "explain-labels", "rows": [{"label": "Merge", "identity": "Merge Join"}], "title": "\u672c\u6784\u5efa\u4e2d\u7684 EXPLAIN \u6807\u7b7e", "columns": [{"key": "label", "label": "\u6587\u672c\u683c\u5f0f\u6807\u7b7e"}, {"key": "identity", "label": "\u7ed3\u6784\u5316\u8282\u70b9\u6807\u8bc6"}]}], "related": [{"url": "/wiki/sql/explain/?v=18", "label": "EXPLAIN"}, {"url": "/docs/18/using-explain.html", "label": "\u4f7f\u7528 EXPLAIN"}, {"url": "/docs/18/parallel-plans.html", "label": "\u5e76\u884c\u8ba1\u5212"}, {"url": "/wiki/guc/enable_mergejoin/?v=18", "label": "enable_mergejoin"}], "release": {"ref": "PostgreSQL 18.6 source archive", "label": "18.6", "major": "18", "channel": "stable", "revision": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f", "source_url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "line": 1424, "path": "src/backend/commands/explain.c", "label": "src/backend/commands/explain.c:1424", "sha256": "34c86d6070224a0e981efef51f79101d6d505e5874f1684ace183034bab14bb4", "archive_sha256": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}, {"url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "line": 302, "path": "src/backend/executor/execProcnode.c", "label": "src/backend/executor/execProcnode.c:302", "sha256": "f8a06a3f539077249b20664b2812433db6d7bd12b2c0ca633525db43d06f112a", "archive_sha256": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}, {"url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "df6726b291493e06be7c43e5664bfb4251267eff66481eaf8e04969c39612b25", "archive_sha256": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}, {"url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "path": "src/include/nodes/plannodes.h", "label": "src/include/nodes/plannodes.h", "sha256": "52422b327a8049fbbb20d8b96008a0fc0a6fafa60f7eff3c695d5b2e83830120", "archive_sha256": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}, {"url": "https://pg.center/docs/18/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 18.6 \u00b7 using-explain", "sha256": "60040c30180093418a0affe56dd27dff9df2504b705b38039589e458bf5c31ed", "language": "en", "original_url": "/docs/18/using-explain.html#USING-EXPLAIN-BASICS"}, {"url": "https://pg.center/docs/18/using-explain.html#USING-EXPLAIN-ANALYZE", "path": "using-explain.html", "label": "PostgreSQL 18.6 \u00b7 using-explain", "sha256": "60040c30180093418a0affe56dd27dff9df2504b705b38039589e458bf5c31ed", "language": "en", "original_url": "/docs/18/using-explain.html#USING-EXPLAIN-ANALYZE"}, {"url": "https://pg.center/docs/18/using-explain.html#USING-EXPLAIN-CAVEATS", "path": "using-explain.html", "label": "PostgreSQL 18.6 \u00b7 using-explain", "sha256": "60040c30180093418a0affe56dd27dff9df2504b705b38039589e458bf5c31ed", "language": "en", "original_url": "/docs/18/using-explain.html#USING-EXPLAIN-CAVEATS"}], "node_tag": "T_MergeJoin", "sections": [{"title": "EXPLAIN \u540d\u79f0\u4e0e\u5c5e\u6027", "paragraphs": ["\u7ed3\u6784\u5316\u683c\u5f0f\u4f7f\u7528\u4e0a\u8ff0 Node Type\u3002\u6587\u672c\u683c\u5f0f\u540d\u79f0\u8fd8\u53ef\u80fd\u5305\u542b\u64cd\u4f5c\u3001\u7b56\u7565\u3001\u8fde\u63a5\u7c7b\u578b\u3001\u626b\u63cf\u65b9\u5411\u6216\u805a\u5408\u9636\u6bb5\u5c5e\u6027\u3002", "\u6b64\u6e90\u7801\u8bb0\u5f55\u7684\u6587\u672c\u540d\u79f0\uff1aMerge.", "\u5e76\u884c\u611f\u77e5\u4e0e\u5e76\u884c\u5b89\u5168\u662f\u4e0d\u540c\u7684\u8ba1\u5212\u5c5e\u6027\u3002\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u5185\u8fd0\u884c\u7684\u8282\u70b9\u4e0d\u4e00\u5b9a\u662f\u5e76\u884c\u611f\u77e5\u8282\u70b9\u3002"]}, {"title": "\u5185\u5b58\u4e0e\u4e34\u65f6\u5b58\u50a8", "paragraphs": ["\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002"]}, {"title": "\u5e76\u884c\u6267\u884c\u4e0e\u8fd0\u884c\u4fe1\u606f\u91c7\u96c6", "paragraphs": ["\u4ee5\u4e0b\u6e90\u7801\u56de\u8c03\u53ef\u4ee5\u534f\u8c03\u6267\u884c\u6216\u6536\u96c6\u5de5\u4f5c\u8fdb\u7a0b\u7684\u6d4b\u91cf\u6570\u636e\u3002\u56de\u8c03\u5b58\u5728\u4e0d\u4ee3\u8868\u8be5\u8282\u70b9\u666e\u904d\u652f\u6301\u5171\u4eab\u5e76\u884c\u626b\u63cf\u6216\u5171\u4eab\u72b6\u6001\u3002", "\u6b64\u6784\u5efa\u7684\u56de\u8c03\uff1anone extracted from this node implementation."]}, {"title": "\u540c\u7248\u672c\u624b\u518c\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u8981\u6c42\u8f93\u5165\u6570\u636e\u6309\u8fde\u63a5\u952e\u6392\u5e8f\u3002\u5728\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u4e24\u4e2a\u8f93\u5165\u90fd\u901a\u8fc7\u7d22\u5f15\u626b\u63cf\u6309\u6b63\u786e\u987a\u5e8f\u8bbf\u95ee\u884c\u800c\u5b8c\u6210\u6392\u5e8f\uff1b\u4e0d\u8fc7\u4e5f\u53ef\u4ee5\u91c7\u7528\u987a\u5e8f\u626b\u63cf\u518d\u6392\u5e8f\u7684\u65b9\u5f0f\u3002\uff08\u5bf9\u4e8e\u9700\u8981\u6392\u5e8f\u5f88\u591a\u884c\u7684\u60c5\u51b5\uff0c\u987a\u5e8f\u626b\u63cf\u52a0\u6392\u5e8f\u5f80\u5f80\u4f1a\u80dc\u8fc7\u7d22\u5f15\u626b\u63cf\uff0c\u56e0\u4e3a\u7d22\u5f15\u626b\u63cf\u9700\u8981\u975e\u987a\u5e8f\u78c1\u76d8\u8bbf\u95ee\u3002\uff09", "\u89c2\u5bdf\u5907\u9009\u8ba1\u5212\u7684\u4e00\u79cd\u65b9\u6cd5\uff0c\u662f\u5229\u7528 \u7b2c 19.7.1 \u8282 \u4e2d\u63cf\u8ff0\u7684\u542f\u7528/\u7981\u7528\u6807\u5fd7\uff0c\u5f3a\u8feb\u89c4\u5212\u5668\u5ffd\u7565\u5b83\u8ba4\u4e3a\u6700\u4fbf\u5b9c\u7684\u7b56\u7565\u3002\uff08\u8fd9\u662f\u4e2a\u7c97\u7cd9\u4f46\u6709\u7528\u7684\u5de5\u5177\u3002\u53e6\u89c1 \u7b2c 14.3 \u8282 \u3002\uff09\u4f8b\u5982\uff0c\u5982\u679c\u6211\u4eec\u5e76\u4e0d\u786e\u4fe1\u524d\u4e00\u4e2a\u793a\u4f8b\u4e2d\u5f52\u5e76\u8fde\u63a5\u771f\u7684\u662f\u6700\u4f73\u8fde\u63a5\u7c7b\u578b\uff0c\u53ef\u4ee5\u8bd5\u8bd5\uff1a", "\u8fd9\u8868\u660e\uff0c\u89c4\u5212\u5668\u8ba4\u4e3a\u5728\u8fd9\u4e2a\u573a\u666f\u4e0b\uff0c\u54c8\u5e0c\u8fde\u63a5\u7684\u4ee3\u4ef7\u51e0\u4e4e\u6bd4\u5f52\u5e76\u8fde\u63a5\u9ad8\u51fa 50%\u3002\u5f53\u7136\uff0c\u63a5\u4e0b\u6765\u7684\u95ee\u9898\u5c31\u662f\u5b83\u662f\u5426\u5224\u65ad\u6b63\u786e\u3002\u6211\u4eec\u53ef\u4ee5\u50cf \u4e0b\u6587 \u6240\u8ff0\uff0c\u4f7f\u7528 EXPLAIN ANALYZE \u6765\u7814\u7a76\u3002", "\u5982\u672c\u4f8b\u6240\u793a\uff0c\u67e5\u8be2\u4e3a INSERT\u3001UPDATE\u3001DELETE \u6216 MERGE \u547d\u4ee4\u65f6\uff0c\u5b9e\u9645\u5e94\u7528\u8868\u53d8\u66f4\u7684\u5de5\u4f5c\u7531\u9876\u5c42 Insert\u3001Update\u3001Delete \u6216 Merge \u8ba1\u5212\u8282\u70b9\u5b8c\u6210\u3002\u5176\u4e0b\u7684\u8ba1\u5212\u8282\u70b9\u8d1f\u8d23\u5b9a\u4f4d\u65e7\u884c\u548c\uff0f\u6216\u8ba1\u7b97\u65b0\u6570\u636e\u3002\u56e0\u6b64\uff0c\u4e0a\u4f8b\u4ecd\u91c7\u7528\u524d\u9762\u89c1\u8fc7\u7684\u4f4d\u56fe\u8868\u626b\u63cf\uff0c\u5176\u8f93\u51fa\u4f20\u7ed9 Update \u8282\u70b9\uff0c\u7531\u540e\u8005\u5b58\u50a8\u66f4\u65b0\u540e\u7684\u884c\u3002\u867d\u7136\u6570\u636e\u4fee\u6539\u8282\u70b9\u53ef\u80fd\u6d88\u8017\u76f8\u5f53\u591a\u7684\u8fd0\u884c\u65f6\u95f4\uff08\u672c\u4f8b\u4e2d\u5360\u4e86\u7edd\u5927\u90e8\u5206\uff09\uff0c\u4f46\u89c4\u5212\u5668\u76ee\u524d\u5e76\u672a\u5c06\u8fd9\u90e8\u5206\u5de5\u4f5c\u8ba1\u5165\u4ee3\u4ef7\u4f30\u7b97\u3002\u8fd9\u662f\u56e0\u4e3a\u4efb\u4f55\u6b63\u786e\u67e5\u8be2\u8ba1\u5212\u9700\u8981\u5b8c\u6210\u7684\u8fd9\u90e8\u5206\u5de5\u4f5c\u90fd\u76f8\u540c\uff0c\u56e0\u6b64\u4e0d\u4f1a\u5f71\u54cd\u89c4\u5212\u51b3\u7b56\u3002", "\u5f53 UPDATE \u3001 DELETE \u6216 MERGE \u547d\u4ee4\u5f71\u54cd\u5206\u533a\u8868\u6216\u7ee7\u627f\u5c42\u6b21\u65f6\uff0c\u8f93\u51fa\u53ef\u80fd\u50cf\u8fd9\u6837\uff1a", "\u5f52\u5e76\u8fde\u63a5\u7684\u6d4b\u91cf\u7ed3\u679c\u4e5f\u53ef\u80fd\u4ea7\u751f\u8bef\u5bfc\u3002\u82e5\u4e00\u4fa7\u8f93\u5165\u5df2\u8017\u5c3d\uff0c\u53e6\u4e00\u4fa7\u7684\u4e0b\u4e00\u4e2a\u952e\u503c\u53c8\u5927\u4e8e\u5df2\u8017\u5c3d\u8f93\u5165\u7684\u6700\u540e\u4e00\u4e2a\u952e\u503c\uff0c\u5c31\u4e0d\u4f1a\u518d\u6709\u5339\u914d\uff0c\u56e0\u6b64\u4f1a\u505c\u6b62\u8bfb\u53d6\u53e6\u4e00\u4fa7\u3002\u8fd9\u6837\u4fbf\u672a\u8bfb\u53d6\u8be5\u5b50\u8282\u70b9\u7684\u5168\u90e8\u884c\uff0c\u7c7b\u4f3c LIMIT \u7684\u60c5\u51b5\u3002\u53e6\u5916\uff0c\u5916\u4fa7\uff08\u7b2c\u4e00\u4e2a\uff09\u5b50\u8282\u70b9\u6709\u91cd\u590d\u952e\u503c\u65f6\uff0c\u5185\u4fa7\uff08\u7b2c\u4e8c\u4e2a\uff09\u5b50\u8282\u70b9\u4f1a\u56de\u9000\u5e76\u91cd\u65b0\u626b\u63cf\u5339\u914d\u8be5\u952e\u503c\u7684\u884c\u3002EXPLAIN ANALYZE \u4f1a\u5c06\u5185\u4fa7\u91cd\u590d\u8f93\u51fa\u7684\u884c\u8ba1\u4f5c\u989d\u5916\u7684\u771f\u5b9e\u884c\u3002\u56e0\u6b64\u5916\u4fa7\u91cd\u590d\u503c\u5f88\u591a\u65f6\uff0c\u5185\u4fa7\u8ba1\u5212\u8282\u70b9\u62a5\u544a\u7684\u5b9e\u9645\u884c\u6570\u53ef\u80fd\u663e\u8457\u8d85\u8fc7\u5185\u4fa7\u5173\u7cfb\u4e2d\u7684\u5b9e\u9645\u884c\u6570\u3002"]}, {"title": "\u672c\u7248\u624b\u518c\u4e2d\u7684\u793a\u4f8b", "blocks": [{"code": "EXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=0.56..233.49 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..643.28 rows=100 width=244)\n         Filter: (unique1 < 100)\n   ->  Index Scan using onek_unique2 on onek t2  (cost=0.28..166.28 rows=1000 width=244)", "source": {"url": "/docs/18/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 18.6 \u00b7 using-explain", "sha256": "60040c30180093418a0affe56dd27dff9df2504b705b38039589e458bf5c31ed"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 18.6 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u53e6\u4e00\u79cd\u53ef\u80fd\u7684\u8fde\u63a5\u65b9\u5f0f\u662f\u5f52\u5e76\u8fde\u63a5\uff0c\u5982\u4e0b\u6240\u793a\uff1a"]}]}, {"title": "\u6267\u884c\u5668\u5b9e\u73b0\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u5bf9\u6ee1\u8db3 ((= outerKey innerKey) ...) \u5f62\u5f0f\u8fde\u63a5\u6761\u4ef6\u7684\u5185\u5916\u4fa7\u5143\u7ec4\u6267\u884c\u8fde\u63a5\u3002\u8fde\u63a5\u6761\u4ef6\u5217\u8868\u7531\u67e5\u8be2\u89c4\u5212\u5668\u63d0\u4f9b\uff0c\u53ef\u4ee5\u5305\u542b\u591a\u4e2a (= outerKey innerKey) \u6761\u4ef6\uff0c\u4ee5\u652f\u6301\u590d\u5408\u6392\u5e8f\u952e\u3002", "\u4e0d\u8fc7\uff0c\u67e5\u8be2\u6267\u884c\u5668\u9700\u8981\u5224\u65ad\u5916\u4fa7\u5143\u7ec4\u662f\u5426\u201c\u5927\u4e8e\uff0f\u5c0f\u4e8e\u201d\u5185\u4fa7\u5143\u7ec4\uff0c\u4ee5\u4fbf\u201c\u540c\u6b65\u201d\u4e24\u4e2a\u5173\u7cfb\u3002\u4f8b\u5982\uff0c\u8003\u8651\u4ee5\u4e0b\u5173\u7cfb\uff1a", "outer: (0 ^1 1 2 5 5 5 6 6 7) current tuple: 1 inner: (1 ^3 5 5 5 5 6) current tuple: 3", "\u4e3a\u7ee7\u7eed\u5f52\u5e76\u8fde\u63a5\uff0c\u6267\u884c\u5668\u9700\u8981\u626b\u63cf\u5185\u5916\u4fa7\u5173\u7cfb\uff0c\u76f4\u5230\u627e\u5230\u5339\u914d\u7684\u5143\u7ec4 5\u3002\u5b83\u9700\u8981\u77e5\u9053\u5f53\u524d\u5185\u4fa7\u5143\u7ec4 3\u201c\u5927\u4e8e\u201d\u5916\u4fa7\u5143\u7ec4 1\uff0c\u56e0\u6b64\u5e94\u5148\u626b\u63cf\u5916\u4fa7\u5173\u7cfb\u4ee5\u5bfb\u627e\u5339\u914d\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002", "\u56e0\u6b64\uff0c\u4e0d\u76f4\u63a5\u6267\u884c\u5f52\u5e76\u8fde\u63a5\u6761\u4ef6\uff0c\u800c\u662f\u5206\u522b\u6c42\u503c\u5de6\u53f3\u952e\u8868\u8fbe\u5f0f\uff0c\u518d\u9010\u5217\u6bd4\u8f83\uff08\u53c2\u89c1 MJCompare\uff09\u3002\u89c4\u5212\u5668\u63d0\u4f9b\u8db3\u591f\u7684\u8f93\u5165\u6392\u5e8f\u4fe1\u606f\uff0c\u8ba9\u6267\u884c\u5668\u786e\u5b9a\u6bd4\u8f83\u65b9\u6cd5\u3002\u53ef\u4ee5\u4f7f\u7528\u76f8\u5e94\u7684 B-tree \u6bd4\u8f83\u51fd\u6570\uff0c\u56e0\u4e3a Postgres \u7684\u6392\u5e8f\u8bed\u4e49\u4ec5\u7531 B-tree \u64cd\u4f5c\u7b26\u5bb6\u65cf\u5b9a\u4e49\u3002"]}, {"code": "case T_MergeJoin:\n\t\t\tpname = \"Merge\";\t/* \"Join\" gets added by jointype switch */\n\t\t\tsname = \"Merge Join\";\n\t\t\tbreak;", "title": "\u6838\u5fc3\u6e90\u7801\u4e2d\u7684 EXPLAIN \u6807\u8bc6"}], "strategies": [], "description": ["\u4f7f\u7528\u5f52\u5e76\u6761\u4ef6\u8fde\u63a5\u6709\u5e8f\u8f93\u5165\u6d41\u3002"], "localization": {"status": "complete", "sources": [{"url": "/docs/18/using-explain.html", "method": "same-major semantic node", "sha256": "b8835ec9adbc70ec150667a6b5443f8d298222dc0cc8c2bd1abb1c1d64895904", "language": "zh", "matched_nodes": ["#USING-EXPLAIN/div[7]/p[51]", "#USING-EXPLAIN/div[7]/p[52]", "#USING-EXPLAIN/div[7]/p[54]", "#USING-EXPLAIN/div[8]/p[29]"]}], "language": "zh", "original_text": {"/versions/18/description/0": "Joins ordered input streams using merge clauses.", "/versions/18/facts/0/label": "Core node tag", "/versions/18/facts/1/label": "Structured EXPLAIN Node Type", "/versions/18/facts/2/label": "Inputs", "/versions/18/facts/2/value": "Ordered outer and inner child plans", "/versions/18/facts/3/label": "Output", "/versions/18/facts/3/value": "Joined tuples according to the selected join type", "/versions/18/facts/4/label": "Executor initializer", "/versions/18/facts/5/label": "Memory mechanism", "/versions/18/tables/0/title": "EXPLAIN labels in this source build", "/versions/18/related/1/label": "Using EXPLAIN", "/versions/18/related/2/label": "Parallel plans", "/versions/18/sections/0/title": "EXPLAIN names and attributes", "/versions/18/sections/1/title": "Memory and temporary storage", "/versions/18/sections/2/title": "Parallel execution and instrumentation", "/versions/18/sections/3/title": "Same-version manual discussion", "/versions/18/sections/4/title": "Examples from this manual build", "/versions/18/sections/5/title": "Executor implementation notes", "/versions/18/sections/6/title": "EXPLAIN identity in core source", "/versions/18/memory/description": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/18/sections/0/paragraphs/0": "Structured formats use the Node Type above. Text-format spellings can also include operation, strategy, join type, scan direction or aggregation-stage attributes.", "/versions/18/sections/0/paragraphs/1": "Text names recorded by this source: Merge.", "/versions/18/sections/0/paragraphs/2": "Parallel-aware and parallel-safe are different plan properties. A node running inside a parallel worker is not necessarily a parallel-aware node.", "/versions/18/sections/1/paragraphs/0": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/18/sections/2/paragraphs/0": "The source callbacks below can coordinate execution or collect worker instrumentation. Their presence is not a blanket claim that this node supports a shared parallel scan or shared state.", "/versions/18/sections/2/paragraphs/1": "Callbacks in this build: none extracted from this node implementation.", "/versions/18/sections/3/paragraphs/0": "Merge join requires its input data to be sorted on the join keys. In this example each input is sorted by using an index scan to visit the rows in the correct order; but a sequential scan and sort could also be used. (Sequential-scan-and-sort frequently beats an index scan for sorting many rows, because of the nonsequential disk access required by the index scan.)", "/versions/18/sections/3/paragraphs/1": "One way to look at variant plans is to force the planner to disregard whatever strategy it thought was the cheapest, using the enable/disable flags described in Section 19.7.1 . (This is a crude tool, but useful. See also Section 14.3 .) For example, if we're unconvinced that merge join is the best join type for the previous example, we could try", "/versions/18/sections/3/paragraphs/2": "which shows that the planner thinks that hash join would be nearly 50% more expensive than merge join for this case. Of course, the next question is whether it's right about that. We can investigate that using EXPLAIN ANALYZE , as discussed below .", "/versions/18/sections/3/paragraphs/3": "As seen in this example, when the query is an INSERT , UPDATE , DELETE , or MERGE command, the actual work of applying the table changes is done by a top-level Insert, Update, Delete, or Merge plan node. The plan nodes underneath this node perform the work of locating the old rows and/or computing the new data. So above, we see the same sort of bitmap table scan we've seen already, and its output is fed to an Update node that stores the updated rows. It's worth noting that although the data-modifying node can take a considerable amount of run time (here, it's consuming the lion's share of the time), the planner does not currently add anything to the cost estimates to account for that work. That's because the work to be done is the same for every correct query plan, so it doesn't affect planning decisions.", "/versions/18/sections/3/paragraphs/4": "When an UPDATE , DELETE , or MERGE command affects a partitioned table or inheritance hierarchy, the output might look like this:", "/versions/18/sections/3/paragraphs/5": "Merge joins also have measurement artifacts that can confuse the unwary. A merge join will stop reading one input if it's exhausted the other input and the next key value in the one input is greater than the last key value of the other input; in such a case there can be no more matches and so no need to scan the rest of the first input. This results in not reading all of one child, with results like those mentioned for LIMIT . Also, if the outer (first) child contains rows with duplicate key values, the inner (second) child is backed up and rescanned for the portion of its rows matching that key value. EXPLAIN ANALYZE counts these repeated emissions of the same inner rows as if they were real additional rows. When there are many outer duplicates, the reported actual row count for the inner child plan node can be significantly larger than the number of rows that are actually in the inner relation.", "/versions/18/sections/5/paragraphs/0": "Merge-join is done by joining the inner and outer tuples satisfying join clauses of the form ((= outerKey innerKey) ...). The join clause list is provided by the query planner and may contain more than one (= outerKey innerKey) clause (for composite sort key).", "/versions/18/sections/5/paragraphs/1": "However, the query executor needs to know whether an outer tuple is \"greater/smaller\" than an inner tuple so that it can \"synchronize\" the two relations. For example, consider the following relations:", "/versions/18/sections/5/paragraphs/3": "To continue the merge-join, the executor needs to scan both inner and outer relations till the matching tuples 5. It needs to know that currently inner tuple 3 is \"greater\" than outer tuple 1 and therefore it should scan the outer relation first to find a matching tuple and so on.", "/versions/18/sections/5/paragraphs/4": "Therefore, rather than directly executing the merge join clauses, we evaluate the left and right key expressions separately and then compare the columns one at a time (see MJCompare). The planner passes us enough information about the sort ordering of the inputs to allow us to determine how to make the comparison. We may use the appropriate btree comparison function, since Postgres' only notion of ordering is specified by btree opfamilies.", "/versions/18/tables/0/columns/0/label": "Text-format label", "/versions/18/tables/0/columns/1/label": "Structured node identity", "/versions/18/sections/4/blocks/0/paragraphs/0": "Example copied from the PostgreSQL 18.6 manual; it was not executed for this collection.", "/versions/18/sections/4/blocks/0/paragraphs/1": "Another possible type of join is a merge join, illustrated here:"}, "fallback_fields": [], "source_language": "en", "original_snapshot_sha256": "36b750b49891ade23131d9581b03e3cc836daa7d11c125d079e38438d978badd"}, "evidence_kind": "source and documentation", "explain_names": ["Merge"], "partial_modes": [], "comparison_data": {"node_tag": "T_MergeJoin", "strategies": [], "text_names": ["Merge"], "initializer": "ExecInitMergeJoin", "partial_modes": [], "memory_mechanism": "unclassified", "parallel_callbacks": []}, "comparison_hash": "b17771ee4d48585afbaba91552e5eb00f05a4b6784aa491387217937a4a30511", "explain_prefixes": ["Parallel", "Async"], "runtime_verified": false, "source_inventory": {"explain": "src/backend/commands/explain.c", "executor": "src/backend/executor/execProcnode.c", "implementation": "src/backend/executor/nodeMergejoin.c"}, "parallel_callbacks": []}, "19": {"facts": [{"label": "\u6838\u5fc3\u8282\u70b9\u6807\u7b7e", "value": "T_MergeJoin"}, {"label": "\u7ed3\u6784\u5316 EXPLAIN \u8282\u70b9\u7c7b\u578b", "value": "Merge Join"}, {"label": "\u8f93\u5165", "value": "\u6709\u5e8f\u7684\u5916\u4fa7\u548c\u5185\u4fa7\u5b50\u8ba1\u5212"}, {"label": "\u8f93\u51fa", "value": "\u6309\u6240\u9009\u8fde\u63a5\u7c7b\u578b\u751f\u6210\u7684\u8fde\u63a5\u5143\u7ec4"}, {"label": "\u6267\u884c\u5668\u521d\u59cb\u5316\u51fd\u6570", "value": "ExecInitMergeJoin"}, {"label": "\u5185\u5b58\u673a\u5236", "value": "unclassified"}], "memory": {"evidence": [{"url": "https://ftp.postgresql.org/pub/source/v19beta4/postgresql-19beta4.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "65c9b61454ef3ed8dae2f6fefbbcb56578829ea6256e00816bd0cd6c72536dc7", "archive_sha256": "83157ee9c599d03b2f7a3d73ef3a56ec24e0e79cc2b3501a64d1364f56398c86"}], "mechanism": "unclassified", "description": "\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002", "source_notes": []}, "tables": [{"key": "explain-labels", "rows": [{"label": "Merge", "identity": "Merge Join"}], "title": "\u672c\u6784\u5efa\u4e2d\u7684 EXPLAIN \u6807\u7b7e", "columns": [{"key": "label", "label": "\u6587\u672c\u683c\u5f0f\u6807\u7b7e"}, {"key": "identity", "label": "\u7ed3\u6784\u5316\u8282\u70b9\u6807\u8bc6"}]}], "related": [{"url": "/wiki/sql/explain/?v=19", "label": "EXPLAIN"}, {"url": "/docs/19/using-explain.html", "label": "\u4f7f\u7528 EXPLAIN"}, {"url": "/docs/19/parallel-plans.html", "label": "\u5e76\u884c\u8ba1\u5212"}, {"url": "/wiki/guc/enable_mergejoin/?v=19", "label": "enable_mergejoin"}], "release": {"ref": "PostgreSQL 19beta4 source archive", "label": "19beta4", "major": "19", "channel": "preview", "revision": "83157ee9c599d03b2f7a3d73ef3a56ec24e0e79cc2b3501a64d1364f56398c86", "source_url": "https://ftp.postgresql.org/pub/source/v19beta4/postgresql-19beta4.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "https://ftp.postgresql.org/pub/source/v19beta4/postgresql-19beta4.tar.bz2", "line": 1436, "path": "src/backend/commands/explain.c", "label": "src/backend/commands/explain.c:1436", "sha256": "8b115b1c194a4b54ae630209a741e293b1df49a9052f10b2de9ca092a48998e3", "archive_sha256": "83157ee9c599d03b2f7a3d73ef3a56ec24e0e79cc2b3501a64d1364f56398c86"}, {"url": "https://ftp.postgresql.org/pub/source/v19beta4/postgresql-19beta4.tar.bz2", "line": 302, "path": "src/backend/executor/execProcnode.c", "label": "src/backend/executor/execProcnode.c:302", "sha256": "5e39b2037bed672da55104229ecc32da5abde44c26bcad01479edcfa044d09ed", "archive_sha256": "83157ee9c599d03b2f7a3d73ef3a56ec24e0e79cc2b3501a64d1364f56398c86"}, {"url": "https://ftp.postgresql.org/pub/source/v19beta4/postgresql-19beta4.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "65c9b61454ef3ed8dae2f6fefbbcb56578829ea6256e00816bd0cd6c72536dc7", "archive_sha256": "83157ee9c599d03b2f7a3d73ef3a56ec24e0e79cc2b3501a64d1364f56398c86"}, {"url": "https://ftp.postgresql.org/pub/source/v19beta4/postgresql-19beta4.tar.bz2", "path": "src/include/nodes/plannodes.h", "label": "src/include/nodes/plannodes.h", "sha256": "1c65d5d6b6c81c71531685843647869bcae630779d815a5036b06e070c6c06c7", "archive_sha256": "83157ee9c599d03b2f7a3d73ef3a56ec24e0e79cc2b3501a64d1364f56398c86"}, {"url": "https://pg.center/docs/19/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 19beta4 \u00b7 using-explain", "sha256": "52f111fbd213e2200146319d01a9dcc2ea90001617d2a28edc52f7954c2dd70b", "language": "en", "original_url": "/docs/19/using-explain.html#USING-EXPLAIN-BASICS"}, {"url": "https://pg.center/docs/19/using-explain.html#USING-EXPLAIN-ANALYZE", "path": "using-explain.html", "label": "PostgreSQL 19beta4 \u00b7 using-explain", "sha256": "52f111fbd213e2200146319d01a9dcc2ea90001617d2a28edc52f7954c2dd70b", "language": "en", "original_url": "/docs/19/using-explain.html#USING-EXPLAIN-ANALYZE"}, {"url": "https://pg.center/docs/19/using-explain.html#USING-EXPLAIN-CAVEATS", "path": "using-explain.html", "label": "PostgreSQL 19beta4 \u00b7 using-explain", "sha256": "52f111fbd213e2200146319d01a9dcc2ea90001617d2a28edc52f7954c2dd70b", "language": "en", "original_url": "/docs/19/using-explain.html#USING-EXPLAIN-CAVEATS"}], "node_tag": "T_MergeJoin", "sections": [{"title": "EXPLAIN \u540d\u79f0\u4e0e\u5c5e\u6027", "paragraphs": ["\u7ed3\u6784\u5316\u683c\u5f0f\u4f7f\u7528\u4e0a\u8ff0 Node Type\u3002\u6587\u672c\u683c\u5f0f\u540d\u79f0\u8fd8\u53ef\u80fd\u5305\u542b\u64cd\u4f5c\u3001\u7b56\u7565\u3001\u8fde\u63a5\u7c7b\u578b\u3001\u626b\u63cf\u65b9\u5411\u6216\u805a\u5408\u9636\u6bb5\u5c5e\u6027\u3002", "\u6b64\u6e90\u7801\u8bb0\u5f55\u7684\u6587\u672c\u540d\u79f0\uff1aMerge.", "\u5e76\u884c\u611f\u77e5\u4e0e\u5e76\u884c\u5b89\u5168\u662f\u4e0d\u540c\u7684\u8ba1\u5212\u5c5e\u6027\u3002\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u5185\u8fd0\u884c\u7684\u8282\u70b9\u4e0d\u4e00\u5b9a\u662f\u5e76\u884c\u611f\u77e5\u8282\u70b9\u3002"]}, {"title": "\u5185\u5b58\u4e0e\u4e34\u65f6\u5b58\u50a8", "paragraphs": ["\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002"]}, {"title": "\u5e76\u884c\u6267\u884c\u4e0e\u8fd0\u884c\u4fe1\u606f\u91c7\u96c6", "paragraphs": ["\u4ee5\u4e0b\u6e90\u7801\u56de\u8c03\u53ef\u4ee5\u534f\u8c03\u6267\u884c\u6216\u6536\u96c6\u5de5\u4f5c\u8fdb\u7a0b\u7684\u6d4b\u91cf\u6570\u636e\u3002\u56de\u8c03\u5b58\u5728\u4e0d\u4ee3\u8868\u8be5\u8282\u70b9\u666e\u904d\u652f\u6301\u5171\u4eab\u5e76\u884c\u626b\u63cf\u6216\u5171\u4eab\u72b6\u6001\u3002", "\u6b64\u6784\u5efa\u7684\u56de\u8c03\uff1anone extracted from this node implementation."]}, {"title": "\u540c\u7248\u672c\u624b\u518c\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u8981\u6c42\u8f93\u5165\u6570\u636e\u6309\u8fde\u63a5\u952e\u6392\u5e8f\u3002\u5728\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u4e24\u4e2a\u8f93\u5165\u90fd\u901a\u8fc7\u7d22\u5f15\u626b\u63cf\u6309\u6b63\u786e\u987a\u5e8f\u8bbf\u95ee\u884c\u800c\u5b8c\u6210\u6392\u5e8f\uff1b\u4e0d\u8fc7\u4e5f\u53ef\u4ee5\u91c7\u7528\u987a\u5e8f\u626b\u63cf\u518d\u6392\u5e8f\u7684\u65b9\u5f0f\u3002\uff08\u5bf9\u4e8e\u9700\u8981\u6392\u5e8f\u5f88\u591a\u884c\u7684\u60c5\u51b5\uff0c\u987a\u5e8f\u626b\u63cf\u52a0\u6392\u5e8f\u5f80\u5f80\u4f1a\u80dc\u8fc7\u7d22\u5f15\u626b\u63cf\uff0c\u56e0\u4e3a\u7d22\u5f15\u626b\u63cf\u9700\u8981\u975e\u987a\u5e8f\u78c1\u76d8\u8bbf\u95ee\u3002\uff09", "\u89c2\u5bdf\u5907\u9009\u8ba1\u5212\u7684\u4e00\u79cd\u65b9\u6cd5\uff0c\u662f\u5229\u7528 \u7b2c 19.7.1 \u8282 \u4e2d\u63cf\u8ff0\u7684\u542f\u7528/\u7981\u7528\u6807\u5fd7\uff0c\u5f3a\u8feb\u89c4\u5212\u5668\u5ffd\u7565\u5b83\u8ba4\u4e3a\u6700\u4fbf\u5b9c\u7684\u7b56\u7565\u3002\uff08\u8fd9\u662f\u4e2a\u7c97\u7cd9\u4f46\u6709\u7528\u7684\u5de5\u5177\u3002\u53e6\u89c1 \u7b2c 14.3 \u8282 \u3002\uff09\u4f8b\u5982\uff0c\u5982\u679c\u6211\u4eec\u5e76\u4e0d\u786e\u4fe1\u524d\u4e00\u4e2a\u793a\u4f8b\u4e2d\u5f52\u5e76\u8fde\u63a5\u771f\u7684\u662f\u6700\u4f73\u8fde\u63a5\u7c7b\u578b\uff0c\u53ef\u4ee5\u8bd5\u8bd5\uff1a", "\u8fd9\u8868\u660e\uff0c\u89c4\u5212\u5668\u8ba4\u4e3a\u5728\u8fd9\u4e2a\u573a\u666f\u4e0b\uff0c\u54c8\u5e0c\u8fde\u63a5\u7684\u4ee3\u4ef7\u51e0\u4e4e\u6bd4\u5f52\u5e76\u8fde\u63a5\u9ad8\u51fa 50%\u3002\u5f53\u7136\uff0c\u63a5\u4e0b\u6765\u7684\u95ee\u9898\u5c31\u662f\u5b83\u662f\u5426\u5224\u65ad\u6b63\u786e\u3002\u6211\u4eec\u53ef\u4ee5\u50cf \u4e0b\u6587 \u6240\u8ff0\uff0c\u4f7f\u7528 EXPLAIN ANALYZE \u6765\u7814\u7a76\u3002", "\u5982\u672c\u4f8b\u6240\u793a\uff0c\u67e5\u8be2\u4e3a INSERT\u3001UPDATE\u3001DELETE \u6216 MERGE \u547d\u4ee4\u65f6\uff0c\u5b9e\u9645\u5e94\u7528\u8868\u53d8\u66f4\u7684\u5de5\u4f5c\u7531\u9876\u5c42 Insert\u3001Update\u3001Delete \u6216 Merge \u8ba1\u5212\u8282\u70b9\u5b8c\u6210\u3002\u5176\u4e0b\u7684\u8ba1\u5212\u8282\u70b9\u8d1f\u8d23\u5b9a\u4f4d\u65e7\u884c\u548c\uff0f\u6216\u8ba1\u7b97\u65b0\u6570\u636e\u3002\u56e0\u6b64\uff0c\u4e0a\u4f8b\u4ecd\u91c7\u7528\u524d\u9762\u89c1\u8fc7\u7684\u4f4d\u56fe\u8868\u626b\u63cf\uff0c\u5176\u8f93\u51fa\u4f20\u7ed9 Update \u8282\u70b9\uff0c\u7531\u540e\u8005\u5b58\u50a8\u66f4\u65b0\u540e\u7684\u884c\u3002\u867d\u7136\u6570\u636e\u4fee\u6539\u8282\u70b9\u53ef\u80fd\u6d88\u8017\u76f8\u5f53\u591a\u7684\u8fd0\u884c\u65f6\u95f4\uff08\u672c\u4f8b\u4e2d\u5360\u4e86\u7edd\u5927\u90e8\u5206\uff09\uff0c\u4f46\u89c4\u5212\u5668\u76ee\u524d\u5e76\u672a\u5c06\u8fd9\u90e8\u5206\u5de5\u4f5c\u8ba1\u5165\u4ee3\u4ef7\u4f30\u7b97\u3002\u8fd9\u662f\u56e0\u4e3a\u4efb\u4f55\u6b63\u786e\u67e5\u8be2\u8ba1\u5212\u9700\u8981\u5b8c\u6210\u7684\u8fd9\u90e8\u5206\u5de5\u4f5c\u90fd\u76f8\u540c\uff0c\u56e0\u6b64\u4e0d\u4f1a\u5f71\u54cd\u89c4\u5212\u51b3\u7b56\u3002", "\u5f53 UPDATE \u3001 DELETE \u6216 MERGE \u547d\u4ee4\u5f71\u54cd\u5206\u533a\u8868\u6216\u7ee7\u627f\u5c42\u6b21\u65f6\uff0c\u8f93\u51fa\u53ef\u80fd\u50cf\u8fd9\u6837\uff1a", "\u5f52\u5e76\u8fde\u63a5\u7684\u6d4b\u91cf\u7ed3\u679c\u4e5f\u53ef\u80fd\u4ea7\u751f\u8bef\u5bfc\u3002\u82e5\u4e00\u4fa7\u8f93\u5165\u5df2\u8017\u5c3d\uff0c\u53e6\u4e00\u4fa7\u7684\u4e0b\u4e00\u4e2a\u952e\u503c\u53c8\u5927\u4e8e\u5df2\u8017\u5c3d\u8f93\u5165\u7684\u6700\u540e\u4e00\u4e2a\u952e\u503c\uff0c\u5c31\u4e0d\u4f1a\u518d\u6709\u5339\u914d\uff0c\u56e0\u6b64\u4f1a\u505c\u6b62\u8bfb\u53d6\u53e6\u4e00\u4fa7\u3002\u8fd9\u6837\u4fbf\u672a\u8bfb\u53d6\u8be5\u5b50\u8282\u70b9\u7684\u5168\u90e8\u884c\uff0c\u7c7b\u4f3c LIMIT \u7684\u60c5\u51b5\u3002\u53e6\u5916\uff0c\u5916\u4fa7\uff08\u7b2c\u4e00\u4e2a\uff09\u5b50\u8282\u70b9\u6709\u91cd\u590d\u952e\u503c\u65f6\uff0c\u5185\u4fa7\uff08\u7b2c\u4e8c\u4e2a\uff09\u5b50\u8282\u70b9\u4f1a\u56de\u9000\u5e76\u91cd\u65b0\u626b\u63cf\u5339\u914d\u8be5\u952e\u503c\u7684\u884c\u3002EXPLAIN ANALYZE \u4f1a\u5c06\u5185\u4fa7\u91cd\u590d\u8f93\u51fa\u7684\u884c\u8ba1\u4f5c\u989d\u5916\u7684\u771f\u5b9e\u884c\u3002\u56e0\u6b64\u5916\u4fa7\u91cd\u590d\u503c\u5f88\u591a\u65f6\uff0c\u5185\u4fa7\u8ba1\u5212\u8282\u70b9\u62a5\u544a\u7684\u5b9e\u9645\u884c\u6570\u53ef\u80fd\u663e\u8457\u8d85\u8fc7\u5185\u4fa7\u5173\u7cfb\u4e2d\u7684\u5b9e\u9645\u884c\u6570\u3002"]}, {"title": "\u672c\u7248\u624b\u518c\u4e2d\u7684\u793a\u4f8b", "blocks": [{"code": "EXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=0.56..233.49 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..643.28 rows=100 width=244)\n         Filter: (unique1 < 100)\n   ->  Index Scan using onek_unique2 on onek t2  (cost=0.28..166.28 rows=1000 width=244)", "source": {"url": "/docs/19/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 19beta4 \u00b7 using-explain", "sha256": "52f111fbd213e2200146319d01a9dcc2ea90001617d2a28edc52f7954c2dd70b"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 19beta4 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u53e6\u4e00\u79cd\u53ef\u80fd\u7684\u8fde\u63a5\u65b9\u5f0f\u662f\u5f52\u5e76\u8fde\u63a5\uff0c\u5982\u4e0b\u6240\u793a\uff1a"]}]}, {"title": "\u6267\u884c\u5668\u5b9e\u73b0\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u5bf9\u6ee1\u8db3 ((= outerKey innerKey) ...) \u5f62\u5f0f\u8fde\u63a5\u6761\u4ef6\u7684\u5185\u5916\u4fa7\u5143\u7ec4\u6267\u884c\u8fde\u63a5\u3002\u8fde\u63a5\u6761\u4ef6\u5217\u8868\u7531\u67e5\u8be2\u89c4\u5212\u5668\u63d0\u4f9b\uff0c\u53ef\u4ee5\u5305\u542b\u591a\u4e2a (= outerKey innerKey) \u6761\u4ef6\uff0c\u4ee5\u652f\u6301\u590d\u5408\u6392\u5e8f\u952e\u3002", "\u4e0d\u8fc7\uff0c\u67e5\u8be2\u6267\u884c\u5668\u9700\u8981\u5224\u65ad\u5916\u4fa7\u5143\u7ec4\u662f\u5426\u201c\u5927\u4e8e\uff0f\u5c0f\u4e8e\u201d\u5185\u4fa7\u5143\u7ec4\uff0c\u4ee5\u4fbf\u201c\u540c\u6b65\u201d\u4e24\u4e2a\u5173\u7cfb\u3002\u4f8b\u5982\uff0c\u8003\u8651\u4ee5\u4e0b\u5173\u7cfb\uff1a", "outer: (0 ^1 1 2 5 5 5 6 6 7) current tuple: 1 inner: (1 ^3 5 5 5 5 6) current tuple: 3", "\u4e3a\u7ee7\u7eed\u5f52\u5e76\u8fde\u63a5\uff0c\u6267\u884c\u5668\u9700\u8981\u626b\u63cf\u5185\u5916\u4fa7\u5173\u7cfb\uff0c\u76f4\u5230\u627e\u5230\u5339\u914d\u7684\u5143\u7ec4 5\u3002\u5b83\u9700\u8981\u77e5\u9053\u5f53\u524d\u5185\u4fa7\u5143\u7ec4 3\u201c\u5927\u4e8e\u201d\u5916\u4fa7\u5143\u7ec4 1\uff0c\u56e0\u6b64\u5e94\u5148\u626b\u63cf\u5916\u4fa7\u5173\u7cfb\u4ee5\u5bfb\u627e\u5339\u914d\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002", "\u56e0\u6b64\uff0c\u4e0d\u76f4\u63a5\u6267\u884c\u5f52\u5e76\u8fde\u63a5\u6761\u4ef6\uff0c\u800c\u662f\u5206\u522b\u6c42\u503c\u5de6\u53f3\u952e\u8868\u8fbe\u5f0f\uff0c\u518d\u9010\u5217\u6bd4\u8f83\uff08\u53c2\u89c1 MJCompare\uff09\u3002\u89c4\u5212\u5668\u63d0\u4f9b\u8db3\u591f\u7684\u8f93\u5165\u6392\u5e8f\u4fe1\u606f\uff0c\u8ba9\u6267\u884c\u5668\u786e\u5b9a\u6bd4\u8f83\u65b9\u6cd5\u3002\u53ef\u4ee5\u4f7f\u7528\u76f8\u5e94\u7684 B-tree \u6bd4\u8f83\u51fd\u6570\uff0c\u56e0\u4e3a Postgres \u7684\u6392\u5e8f\u8bed\u4e49\u4ec5\u7531 B-tree \u64cd\u4f5c\u7b26\u5bb6\u65cf\u5b9a\u4e49\u3002"]}, {"code": "case T_MergeJoin:\n\t\t\tpname = \"Merge\";\t/* \"Join\" gets added by jointype switch */\n\t\t\tsname = \"Merge Join\";\n\t\t\tbreak;", "title": "\u6838\u5fc3\u6e90\u7801\u4e2d\u7684 EXPLAIN \u6807\u8bc6"}], "strategies": [], "description": ["\u4f7f\u7528\u5f52\u5e76\u6761\u4ef6\u8fde\u63a5\u6709\u5e8f\u8f93\u5165\u6d41\u3002"], "localization": {"status": "complete", "sources": [{"url": "/docs/19/using-explain.html", "method": "same-major semantic node", "sha256": "7cc78f59bf29afb1811ece53e9d5c572a3f634d66d7422fb8761f19bc6811492", "language": "zh", "matched_nodes": ["#USING-EXPLAIN/div[7]/p[51]", "#USING-EXPLAIN/div[7]/p[52]", "#USING-EXPLAIN/div[7]/p[54]", "#USING-EXPLAIN/div[8]/p[32]"]}], "language": "zh", "original_text": {"/versions/19/description/0": "Joins ordered input streams using merge clauses.", "/versions/19/facts/0/label": "Core node tag", "/versions/19/facts/1/label": "Structured EXPLAIN Node Type", "/versions/19/facts/2/label": "Inputs", "/versions/19/facts/2/value": "Ordered outer and inner child plans", "/versions/19/facts/3/label": "Output", "/versions/19/facts/3/value": "Joined tuples according to the selected join type", "/versions/19/facts/4/label": "Executor initializer", "/versions/19/facts/5/label": "Memory mechanism", "/versions/19/tables/0/title": "EXPLAIN labels in this source build", "/versions/19/related/1/label": "Using EXPLAIN", "/versions/19/related/2/label": "Parallel plans", "/versions/19/sections/0/title": "EXPLAIN names and attributes", "/versions/19/sections/1/title": "Memory and temporary storage", "/versions/19/sections/2/title": "Parallel execution and instrumentation", "/versions/19/sections/3/title": "Same-version manual discussion", "/versions/19/sections/4/title": "Examples from this manual build", "/versions/19/sections/5/title": "Executor implementation notes", "/versions/19/sections/6/title": "EXPLAIN identity in core source", "/versions/19/memory/description": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/19/sections/0/paragraphs/0": "Structured formats use the Node Type above. Text-format spellings can also include operation, strategy, join type, scan direction or aggregation-stage attributes.", "/versions/19/sections/0/paragraphs/1": "Text names recorded by this source: Merge.", "/versions/19/sections/0/paragraphs/2": "Parallel-aware and parallel-safe are different plan properties. A node running inside a parallel worker is not necessarily a parallel-aware node.", "/versions/19/sections/1/paragraphs/0": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/19/sections/2/paragraphs/0": "The source callbacks below can coordinate execution or collect worker instrumentation. Their presence is not a blanket claim that this node supports a shared parallel scan or shared state.", "/versions/19/sections/2/paragraphs/1": "Callbacks in this build: none extracted from this node implementation.", "/versions/19/sections/3/paragraphs/0": "Merge join requires its input data to be sorted on the join keys. In this example each input is sorted by using an index scan to visit the rows in the correct order; but a sequential scan and sort could also be used. (Sequential-scan-and-sort frequently beats an index scan for sorting many rows, because of the nonsequential disk access required by the index scan.)", "/versions/19/sections/3/paragraphs/1": "One way to look at variant plans is to force the planner to disregard whatever strategy it thought was the cheapest, using the enable/disable flags described in Section 19.7.1 . (This is a crude tool, but useful. See also Section 14.3 .) For example, if we're unconvinced that merge join is the best join type for the previous example, we could try", "/versions/19/sections/3/paragraphs/2": "which shows that the planner thinks that hash join would be nearly 50% more expensive than merge join for this case. Of course, the next question is whether it's right about that. We can investigate that using EXPLAIN ANALYZE , as discussed below .", "/versions/19/sections/3/paragraphs/3": "As seen in this example, when the query is an INSERT , UPDATE , DELETE , or MERGE command, the actual work of applying the table changes is done by a top-level Insert, Update, Delete, or Merge plan node. The plan nodes underneath this node perform the work of locating the old rows and/or computing the new data. So above, we see the same sort of bitmap table scan we've seen already, and its output is fed to an Update node that stores the updated rows. It's worth noting that although the data-modifying node can take a considerable amount of run time (here, it's consuming the lion's share of the time), the planner does not currently add anything to the cost estimates to account for that work. That's because the work to be done is the same for every correct query plan, so it doesn't affect planning decisions.", "/versions/19/sections/3/paragraphs/4": "When an UPDATE , DELETE , or MERGE command affects a partitioned table or inheritance hierarchy, the output might look like this:", "/versions/19/sections/3/paragraphs/5": "Merge joins also have measurement artifacts that can confuse the unwary. A merge join will stop reading one input if it's exhausted the other input and the next key value in the one input is greater than the last key value of the other input; in such a case there can be no more matches and so no need to scan the rest of the first input. This results in not reading all of one child, with results like those mentioned for LIMIT . Also, if the outer (first) child contains rows with duplicate key values, the inner (second) child is backed up and rescanned for the portion of its rows matching that key value. EXPLAIN ANALYZE counts these repeated emissions of the same inner rows as if they were real additional rows. When there are many outer duplicates, the reported actual row count for the inner child plan node can be significantly larger than the number of rows that are actually in the inner relation.", "/versions/19/sections/5/paragraphs/0": "Merge-join is done by joining the inner and outer tuples satisfying join clauses of the form ((= outerKey innerKey) ...). The join clause list is provided by the query planner and may contain more than one (= outerKey innerKey) clause (for composite sort key).", "/versions/19/sections/5/paragraphs/1": "However, the query executor needs to know whether an outer tuple is \"greater/smaller\" than an inner tuple so that it can \"synchronize\" the two relations. For example, consider the following relations:", "/versions/19/sections/5/paragraphs/3": "To continue the merge-join, the executor needs to scan both inner and outer relations till the matching tuples 5. It needs to know that currently inner tuple 3 is \"greater\" than outer tuple 1 and therefore it should scan the outer relation first to find a matching tuple and so on.", "/versions/19/sections/5/paragraphs/4": "Therefore, rather than directly executing the merge join clauses, we evaluate the left and right key expressions separately and then compare the columns one at a time (see MJCompare). The planner passes us enough information about the sort ordering of the inputs to allow us to determine how to make the comparison. We may use the appropriate btree comparison function, since Postgres' only notion of ordering is specified by btree opfamilies.", "/versions/19/tables/0/columns/0/label": "Text-format label", "/versions/19/tables/0/columns/1/label": "Structured node identity", "/versions/19/sections/4/blocks/0/paragraphs/0": "Example copied from the PostgreSQL 19beta4 manual; it was not executed for this collection.", "/versions/19/sections/4/blocks/0/paragraphs/1": "Another possible type of join is a merge join, illustrated here:"}, "fallback_fields": [], "source_language": "en", "original_snapshot_sha256": "569ee1913f7e515e2fb815507627b8444b1437737210c4bc54fffe11196ff76c"}, "evidence_kind": "source and documentation", "explain_names": ["Merge"], "partial_modes": [], "comparison_data": {"node_tag": "T_MergeJoin", "strategies": [], "text_names": ["Merge"], "initializer": "ExecInitMergeJoin", "partial_modes": [], "memory_mechanism": "unclassified", "parallel_callbacks": []}, "comparison_hash": "b17771ee4d48585afbaba91552e5eb00f05a4b6784aa491387217937a4a30511", "explain_prefixes": ["Parallel", "Async"], "runtime_verified": false, "source_inventory": {"explain": "src/backend/commands/explain.c", "executor": "src/backend/executor/execProcnode.c", "implementation": "src/backend/executor/nodeMergejoin.c"}, "parallel_callbacks": []}, "20": {"facts": [{"label": "\u6838\u5fc3\u8282\u70b9\u6807\u7b7e", "value": "T_MergeJoin"}, {"label": "\u7ed3\u6784\u5316 EXPLAIN \u8282\u70b9\u7c7b\u578b", "value": "Merge Join"}, {"label": "\u8f93\u5165", "value": "\u6709\u5e8f\u7684\u5916\u4fa7\u548c\u5185\u4fa7\u5b50\u8ba1\u5212"}, {"label": "\u8f93\u51fa", "value": "\u6309\u6240\u9009\u8fde\u63a5\u7c7b\u578b\u751f\u6210\u7684\u8fde\u63a5\u5143\u7ec4"}, {"label": "\u6267\u884c\u5668\u521d\u59cb\u5316\u51fd\u6570", "value": "ExecInitMergeJoin"}, {"label": "\u5185\u5b58\u673a\u5236", "value": "unclassified"}], "memory": {"evidence": [{"url": "https://ftp.postgresql.org/pub/snapshot/dev/postgresql-snapshot.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "3ed455579c351eabe38bb89513d3432379ebda43156cabc87ffdd9ebd7409aed", "archive_sha256": "4d3346909b201ac1648232cf290462a7070c119326f56196f1f0253ed80fae41"}], "mechanism": "unclassified", "description": "\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002", "source_notes": []}, "tables": [{"key": "explain-labels", "rows": [{"label": "Merge", "identity": "Merge Join"}], "title": "\u672c\u6784\u5efa\u4e2d\u7684 EXPLAIN \u6807\u7b7e", "columns": [{"key": "label", "label": "\u6587\u672c\u683c\u5f0f\u6807\u7b7e"}, {"key": "identity", "label": "\u7ed3\u6784\u5316\u8282\u70b9\u6807\u8bc6"}]}], "related": [{"url": "/wiki/sql/explain/?v=20", "label": "EXPLAIN"}, {"url": "/docs/devel/using-explain.html", "label": "\u4f7f\u7528 EXPLAIN"}, {"url": "/docs/devel/parallel-plans.html", "label": "\u5e76\u884c\u8ba1\u5212"}, {"url": "/wiki/guc/enable_mergejoin/?v=20", "label": "enable_mergejoin"}], "release": {"ref": "PostgreSQL 20devel source archive", "label": "20devel", "major": "20", "channel": "devel", "revision": "4d3346909b201ac1648232cf290462a7070c119326f56196f1f0253ed80fae41", "source_url": "https://ftp.postgresql.org/pub/snapshot/dev/postgresql-snapshot.tar.bz2", "source_snapshot_utc": "26-Sep-2026 20:22"}, "sources": [{"url": "https://ftp.postgresql.org/pub/snapshot/dev/postgresql-snapshot.tar.bz2", "line": 1436, "path": "src/backend/commands/explain.c", "label": "src/backend/commands/explain.c:1436", "sha256": "13402758013520451539427b5993db06d463ca11c4e2d4cc5444e82367688077", "archive_sha256": "4d3346909b201ac1648232cf290462a7070c119326f56196f1f0253ed80fae41"}, {"url": "https://ftp.postgresql.org/pub/snapshot/dev/postgresql-snapshot.tar.bz2", "line": 302, "path": "src/backend/executor/execProcnode.c", "label": "src/backend/executor/execProcnode.c:302", "sha256": "5e39b2037bed672da55104229ecc32da5abde44c26bcad01479edcfa044d09ed", "archive_sha256": "4d3346909b201ac1648232cf290462a7070c119326f56196f1f0253ed80fae41"}, {"url": "https://ftp.postgresql.org/pub/snapshot/dev/postgresql-snapshot.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "3ed455579c351eabe38bb89513d3432379ebda43156cabc87ffdd9ebd7409aed", "archive_sha256": "4d3346909b201ac1648232cf290462a7070c119326f56196f1f0253ed80fae41"}, {"url": "https://ftp.postgresql.org/pub/snapshot/dev/postgresql-snapshot.tar.bz2", "path": "src/include/nodes/plannodes.h", "label": "src/include/nodes/plannodes.h", "sha256": "7a94ed1652f0d74d50c39971d1cd3e8051dbc0d6058f31b6de71a433ca343521", "archive_sha256": "4d3346909b201ac1648232cf290462a7070c119326f56196f1f0253ed80fae41"}, {"url": "https://pg.center/docs/devel/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 20devel \u00b7 using-explain", "sha256": "99cfea3035876ea63f88b75ba8c964b51a32a70606544e09f769c0b60a234b31", "language": "en", "original_url": "/docs/devel/using-explain.html#USING-EXPLAIN-BASICS"}, {"url": "https://pg.center/docs/devel/using-explain.html#USING-EXPLAIN-ANALYZE", "path": "using-explain.html", "label": "PostgreSQL 20devel \u00b7 using-explain", "sha256": "99cfea3035876ea63f88b75ba8c964b51a32a70606544e09f769c0b60a234b31", "language": "en", "original_url": "/docs/devel/using-explain.html#USING-EXPLAIN-ANALYZE"}, {"url": "https://pg.center/docs/devel/using-explain.html#USING-EXPLAIN-CAVEATS", "path": "using-explain.html", "label": "PostgreSQL 20devel \u00b7 using-explain", "sha256": "99cfea3035876ea63f88b75ba8c964b51a32a70606544e09f769c0b60a234b31", "language": "en", "original_url": "/docs/devel/using-explain.html#USING-EXPLAIN-CAVEATS"}], "node_tag": "T_MergeJoin", "sections": [{"title": "EXPLAIN \u540d\u79f0\u4e0e\u5c5e\u6027", "paragraphs": ["\u7ed3\u6784\u5316\u683c\u5f0f\u4f7f\u7528\u4e0a\u8ff0 Node Type\u3002\u6587\u672c\u683c\u5f0f\u540d\u79f0\u8fd8\u53ef\u80fd\u5305\u542b\u64cd\u4f5c\u3001\u7b56\u7565\u3001\u8fde\u63a5\u7c7b\u578b\u3001\u626b\u63cf\u65b9\u5411\u6216\u805a\u5408\u9636\u6bb5\u5c5e\u6027\u3002", "\u6b64\u6e90\u7801\u8bb0\u5f55\u7684\u6587\u672c\u540d\u79f0\uff1aMerge.", "\u5e76\u884c\u611f\u77e5\u4e0e\u5e76\u884c\u5b89\u5168\u662f\u4e0d\u540c\u7684\u8ba1\u5212\u5c5e\u6027\u3002\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u5185\u8fd0\u884c\u7684\u8282\u70b9\u4e0d\u4e00\u5b9a\u662f\u5e76\u884c\u611f\u77e5\u8282\u70b9\u3002"]}, {"title": "\u5185\u5b58\u4e0e\u4e34\u65f6\u5b58\u50a8", "paragraphs": ["\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002"]}, {"title": "\u5e76\u884c\u6267\u884c\u4e0e\u8fd0\u884c\u4fe1\u606f\u91c7\u96c6", "paragraphs": ["\u4ee5\u4e0b\u6e90\u7801\u56de\u8c03\u53ef\u4ee5\u534f\u8c03\u6267\u884c\u6216\u6536\u96c6\u5de5\u4f5c\u8fdb\u7a0b\u7684\u6d4b\u91cf\u6570\u636e\u3002\u56de\u8c03\u5b58\u5728\u4e0d\u4ee3\u8868\u8be5\u8282\u70b9\u666e\u904d\u652f\u6301\u5171\u4eab\u5e76\u884c\u626b\u63cf\u6216\u5171\u4eab\u72b6\u6001\u3002", "\u6b64\u6784\u5efa\u7684\u56de\u8c03\uff1anone extracted from this node implementation."]}, {"title": "\u540c\u7248\u672c\u624b\u518c\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u8981\u6c42\u8f93\u5165\u6570\u636e\u6309\u8fde\u63a5\u952e\u6392\u5e8f\u3002\u5728\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u4e24\u4e2a\u8f93\u5165\u90fd\u901a\u8fc7\u7d22\u5f15\u626b\u63cf\u6309\u6b63\u786e\u987a\u5e8f\u8bbf\u95ee\u884c\u800c\u5b8c\u6210\u6392\u5e8f\uff1b\u4e0d\u8fc7\u4e5f\u53ef\u4ee5\u91c7\u7528\u987a\u5e8f\u626b\u63cf\u518d\u6392\u5e8f\u7684\u65b9\u5f0f\u3002\uff08\u5bf9\u4e8e\u9700\u8981\u6392\u5e8f\u5f88\u591a\u884c\u7684\u60c5\u51b5\uff0c\u987a\u5e8f\u626b\u63cf\u52a0\u6392\u5e8f\u5f80\u5f80\u4f1a\u80dc\u8fc7\u7d22\u5f15\u626b\u63cf\uff0c\u56e0\u4e3a\u7d22\u5f15\u626b\u63cf\u9700\u8981\u975e\u987a\u5e8f\u78c1\u76d8\u8bbf\u95ee\u3002\uff09", "\u89c2\u5bdf\u5907\u9009\u8ba1\u5212\u7684\u4e00\u79cd\u65b9\u6cd5\uff0c\u662f\u5229\u7528 \u7b2c 19.7.1 \u8282 \u4e2d\u63cf\u8ff0\u7684\u542f\u7528/\u7981\u7528\u6807\u5fd7\uff0c\u5f3a\u8feb\u89c4\u5212\u5668\u5ffd\u7565\u5b83\u8ba4\u4e3a\u6700\u4fbf\u5b9c\u7684\u7b56\u7565\u3002\uff08\u8fd9\u662f\u4e2a\u7c97\u7cd9\u4f46\u6709\u7528\u7684\u5de5\u5177\u3002\u53e6\u89c1 \u7b2c 14.3 \u8282 \u3002\uff09\u4f8b\u5982\uff0c\u5982\u679c\u6211\u4eec\u5e76\u4e0d\u786e\u4fe1\u524d\u4e00\u4e2a\u793a\u4f8b\u4e2d\u5f52\u5e76\u8fde\u63a5\u771f\u7684\u662f\u6700\u4f73\u8fde\u63a5\u7c7b\u578b\uff0c\u53ef\u4ee5\u8bd5\u8bd5\uff1a", "\u8fd9\u8868\u660e\uff0c\u89c4\u5212\u5668\u8ba4\u4e3a\u5728\u8fd9\u4e2a\u573a\u666f\u4e0b\uff0c\u54c8\u5e0c\u8fde\u63a5\u7684\u4ee3\u4ef7\u51e0\u4e4e\u6bd4\u5f52\u5e76\u8fde\u63a5\u9ad8\u51fa 50%\u3002\u5f53\u7136\uff0c\u63a5\u4e0b\u6765\u7684\u95ee\u9898\u5c31\u662f\u5b83\u662f\u5426\u5224\u65ad\u6b63\u786e\u3002\u6211\u4eec\u53ef\u4ee5\u50cf \u4e0b\u6587 \u6240\u8ff0\uff0c\u4f7f\u7528 EXPLAIN ANALYZE \u6765\u7814\u7a76\u3002", "\u5982\u672c\u4f8b\u6240\u793a\uff0c\u67e5\u8be2\u4e3a INSERT\u3001UPDATE\u3001DELETE \u6216 MERGE \u547d\u4ee4\u65f6\uff0c\u5b9e\u9645\u5e94\u7528\u8868\u53d8\u66f4\u7684\u5de5\u4f5c\u7531\u9876\u5c42 Insert\u3001Update\u3001Delete \u6216 Merge \u8ba1\u5212\u8282\u70b9\u5b8c\u6210\u3002\u5176\u4e0b\u7684\u8ba1\u5212\u8282\u70b9\u8d1f\u8d23\u5b9a\u4f4d\u65e7\u884c\u548c\uff0f\u6216\u8ba1\u7b97\u65b0\u6570\u636e\u3002\u56e0\u6b64\uff0c\u4e0a\u4f8b\u4ecd\u91c7\u7528\u524d\u9762\u89c1\u8fc7\u7684\u4f4d\u56fe\u8868\u626b\u63cf\uff0c\u5176\u8f93\u51fa\u4f20\u7ed9 Update \u8282\u70b9\uff0c\u7531\u540e\u8005\u5b58\u50a8\u66f4\u65b0\u540e\u7684\u884c\u3002\u867d\u7136\u6570\u636e\u4fee\u6539\u8282\u70b9\u53ef\u80fd\u6d88\u8017\u76f8\u5f53\u591a\u7684\u8fd0\u884c\u65f6\u95f4\uff08\u672c\u4f8b\u4e2d\u5360\u4e86\u7edd\u5927\u90e8\u5206\uff09\uff0c\u4f46\u89c4\u5212\u5668\u76ee\u524d\u5e76\u672a\u5c06\u8fd9\u90e8\u5206\u5de5\u4f5c\u8ba1\u5165\u4ee3\u4ef7\u4f30\u7b97\u3002\u8fd9\u662f\u56e0\u4e3a\u4efb\u4f55\u6b63\u786e\u67e5\u8be2\u8ba1\u5212\u9700\u8981\u5b8c\u6210\u7684\u8fd9\u90e8\u5206\u5de5\u4f5c\u90fd\u76f8\u540c\uff0c\u56e0\u6b64\u4e0d\u4f1a\u5f71\u54cd\u89c4\u5212\u51b3\u7b56\u3002", "\u5f53 UPDATE \u3001 DELETE \u6216 MERGE \u547d\u4ee4\u5f71\u54cd\u5206\u533a\u8868\u6216\u7ee7\u627f\u5c42\u6b21\u65f6\uff0c\u8f93\u51fa\u53ef\u80fd\u50cf\u8fd9\u6837\uff1a", "\u5f52\u5e76\u8fde\u63a5\u7684\u6d4b\u91cf\u7ed3\u679c\u4e5f\u53ef\u80fd\u4ea7\u751f\u8bef\u5bfc\u3002\u82e5\u4e00\u4fa7\u8f93\u5165\u5df2\u8017\u5c3d\uff0c\u53e6\u4e00\u4fa7\u7684\u4e0b\u4e00\u4e2a\u952e\u503c\u53c8\u5927\u4e8e\u5df2\u8017\u5c3d\u8f93\u5165\u7684\u6700\u540e\u4e00\u4e2a\u952e\u503c\uff0c\u5c31\u4e0d\u4f1a\u518d\u6709\u5339\u914d\uff0c\u56e0\u6b64\u4f1a\u505c\u6b62\u8bfb\u53d6\u53e6\u4e00\u4fa7\u3002\u8fd9\u6837\u4fbf\u672a\u8bfb\u53d6\u8be5\u5b50\u8282\u70b9\u7684\u5168\u90e8\u884c\uff0c\u7c7b\u4f3c LIMIT \u7684\u60c5\u51b5\u3002\u53e6\u5916\uff0c\u5916\u4fa7\uff08\u7b2c\u4e00\u4e2a\uff09\u5b50\u8282\u70b9\u6709\u91cd\u590d\u952e\u503c\u65f6\uff0c\u5185\u4fa7\uff08\u7b2c\u4e8c\u4e2a\uff09\u5b50\u8282\u70b9\u4f1a\u56de\u9000\u5e76\u91cd\u65b0\u626b\u63cf\u5339\u914d\u8be5\u952e\u503c\u7684\u884c\u3002EXPLAIN ANALYZE \u4f1a\u5c06\u5185\u4fa7\u91cd\u590d\u8f93\u51fa\u7684\u884c\u8ba1\u4f5c\u989d\u5916\u7684\u771f\u5b9e\u884c\u3002\u56e0\u6b64\u5916\u4fa7\u91cd\u590d\u503c\u5f88\u591a\u65f6\uff0c\u5185\u4fa7\u8ba1\u5212\u8282\u70b9\u62a5\u544a\u7684\u5b9e\u9645\u884c\u6570\u53ef\u80fd\u663e\u8457\u8d85\u8fc7\u5185\u4fa7\u5173\u7cfb\u4e2d\u7684\u5b9e\u9645\u884c\u6570\u3002"]}, {"title": "\u672c\u7248\u624b\u518c\u4e2d\u7684\u793a\u4f8b", "blocks": [{"code": "EXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=0.56..233.49 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..643.28 rows=100 width=244)\n         Filter: (unique1 < 100)\n   ->  Index Scan using onek_unique2 on onek t2  (cost=0.28..166.28 rows=1000 width=244)", "source": {"url": "/docs/devel/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 20devel \u00b7 using-explain", "sha256": "99cfea3035876ea63f88b75ba8c964b51a32a70606544e09f769c0b60a234b31"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 20devel \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u53e6\u4e00\u79cd\u53ef\u80fd\u7684\u8fde\u63a5\u65b9\u5f0f\u662f\u5f52\u5e76\u8fde\u63a5\uff0c\u5982\u4e0b\u6240\u793a\uff1a"]}]}, {"title": "\u6267\u884c\u5668\u5b9e\u73b0\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u5bf9\u6ee1\u8db3 ((= outerKey innerKey) ...) \u5f62\u5f0f\u8fde\u63a5\u6761\u4ef6\u7684\u5185\u5916\u4fa7\u5143\u7ec4\u6267\u884c\u8fde\u63a5\u3002\u8fde\u63a5\u6761\u4ef6\u5217\u8868\u7531\u67e5\u8be2\u89c4\u5212\u5668\u63d0\u4f9b\uff0c\u53ef\u4ee5\u5305\u542b\u591a\u4e2a (= outerKey innerKey) \u6761\u4ef6\uff0c\u4ee5\u652f\u6301\u590d\u5408\u6392\u5e8f\u952e\u3002", "\u4e0d\u8fc7\uff0c\u67e5\u8be2\u6267\u884c\u5668\u9700\u8981\u5224\u65ad\u5916\u4fa7\u5143\u7ec4\u662f\u5426\u201c\u5927\u4e8e\uff0f\u5c0f\u4e8e\u201d\u5185\u4fa7\u5143\u7ec4\uff0c\u4ee5\u4fbf\u201c\u540c\u6b65\u201d\u4e24\u4e2a\u5173\u7cfb\u3002\u4f8b\u5982\uff0c\u8003\u8651\u4ee5\u4e0b\u5173\u7cfb\uff1a", "outer: (0 ^1 1 2 5 5 5 6 6 7) current tuple: 1 inner: (1 ^3 5 5 5 5 6) current tuple: 3", "\u4e3a\u7ee7\u7eed\u5f52\u5e76\u8fde\u63a5\uff0c\u6267\u884c\u5668\u9700\u8981\u626b\u63cf\u5185\u5916\u4fa7\u5173\u7cfb\uff0c\u76f4\u5230\u627e\u5230\u5339\u914d\u7684\u5143\u7ec4 5\u3002\u5b83\u9700\u8981\u77e5\u9053\u5f53\u524d\u5185\u4fa7\u5143\u7ec4 3\u201c\u5927\u4e8e\u201d\u5916\u4fa7\u5143\u7ec4 1\uff0c\u56e0\u6b64\u5e94\u5148\u626b\u63cf\u5916\u4fa7\u5173\u7cfb\u4ee5\u5bfb\u627e\u5339\u914d\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002", "\u56e0\u6b64\uff0c\u4e0d\u76f4\u63a5\u6267\u884c\u5f52\u5e76\u8fde\u63a5\u6761\u4ef6\uff0c\u800c\u662f\u5206\u522b\u6c42\u503c\u5de6\u53f3\u952e\u8868\u8fbe\u5f0f\uff0c\u518d\u9010\u5217\u6bd4\u8f83\uff08\u53c2\u89c1 MJCompare\uff09\u3002\u89c4\u5212\u5668\u63d0\u4f9b\u8db3\u591f\u7684\u8f93\u5165\u6392\u5e8f\u4fe1\u606f\uff0c\u8ba9\u6267\u884c\u5668\u786e\u5b9a\u6bd4\u8f83\u65b9\u6cd5\u3002\u53ef\u4ee5\u4f7f\u7528\u76f8\u5e94\u7684 B-tree \u6bd4\u8f83\u51fd\u6570\uff0c\u56e0\u4e3a Postgres \u7684\u6392\u5e8f\u8bed\u4e49\u4ec5\u7531 B-tree \u64cd\u4f5c\u7b26\u5bb6\u65cf\u5b9a\u4e49\u3002"]}, {"code": "case T_MergeJoin:\n\t\t\tpname = \"Merge\";\t/* \"Join\" gets added by jointype switch */\n\t\t\tsname = \"Merge Join\";\n\t\t\tbreak;", "title": "\u6838\u5fc3\u6e90\u7801\u4e2d\u7684 EXPLAIN \u6807\u8bc6"}], "strategies": [], "description": ["\u4f7f\u7528\u5f52\u5e76\u6761\u4ef6\u8fde\u63a5\u6709\u5e8f\u8f93\u5165\u6d41\u3002"], "localization": {"status": "complete", "sources": [{"url": "/docs/devel/using-explain.html", "method": "same-major semantic node", "sha256": "2744ee0e88d132c504bf5e102765edaabd393eb12c59294093db6d90b26dd65c", "language": "zh", "matched_nodes": ["#USING-EXPLAIN/div[7]/p[51]", "#USING-EXPLAIN/div[7]/p[52]", "#USING-EXPLAIN/div[7]/p[54]", "#USING-EXPLAIN/div[8]/p[32]"]}], "language": "zh", "original_text": {"/summary": "Joins ordered input streams using merge clauses.", "/category": "Join", "/versions/20/description/0": "Joins ordered input streams using merge clauses.", "/versions/20/facts/0/label": "Core node tag", "/versions/20/facts/1/label": "Structured EXPLAIN Node Type", "/versions/20/facts/2/label": "Inputs", "/versions/20/facts/2/value": "Ordered outer and inner child plans", "/versions/20/facts/3/label": "Output", "/versions/20/facts/3/value": "Joined tuples according to the selected join type", "/versions/20/facts/4/label": "Executor initializer", "/versions/20/facts/5/label": "Memory mechanism", "/versions/20/tables/0/title": "EXPLAIN labels in this source build", "/versions/20/related/1/label": "Using EXPLAIN", "/versions/20/related/2/label": "Parallel plans", "/versions/20/sections/0/title": "EXPLAIN names and attributes", "/versions/20/sections/1/title": "Memory and temporary storage", "/versions/20/sections/2/title": "Parallel execution and instrumentation", "/versions/20/sections/3/title": "Same-version manual discussion", "/versions/20/sections/4/title": "Examples from this manual build", "/versions/20/sections/5/title": "Executor implementation notes", "/versions/20/sections/6/title": "EXPLAIN identity in core source", "/versions/20/memory/description": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/20/sections/0/paragraphs/0": "Structured formats use the Node Type above. Text-format spellings can also include operation, strategy, join type, scan direction or aggregation-stage attributes.", "/versions/20/sections/0/paragraphs/1": "Text names recorded by this source: Merge.", "/versions/20/sections/0/paragraphs/2": "Parallel-aware and parallel-safe are different plan properties. A node running inside a parallel worker is not necessarily a parallel-aware node.", "/versions/20/sections/1/paragraphs/0": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/20/sections/2/paragraphs/0": "The source callbacks below can coordinate execution or collect worker instrumentation. Their presence is not a blanket claim that this node supports a shared parallel scan or shared state.", "/versions/20/sections/2/paragraphs/1": "Callbacks in this build: none extracted from this node implementation.", "/versions/20/sections/3/paragraphs/0": "Merge join requires its input data to be sorted on the join keys. In this example each input is sorted by using an index scan to visit the rows in the correct order; but a sequential scan and sort could also be used. (Sequential-scan-and-sort frequently beats an index scan for sorting many rows, because of the nonsequential disk access required by the index scan.)", "/versions/20/sections/3/paragraphs/1": "One way to look at variant plans is to force the planner to disregard whatever strategy it thought was the cheapest, using the enable/disable flags described in Section 19.7.1 . (This is a crude tool, but useful. See also Section 14.3 .) For example, if we're unconvinced that merge join is the best join type for the previous example, we could try", "/versions/20/sections/3/paragraphs/2": "which shows that the planner thinks that hash join would be nearly 50% more expensive than merge join for this case. Of course, the next question is whether it's right about that. We can investigate that using EXPLAIN ANALYZE , as discussed below .", "/versions/20/sections/3/paragraphs/3": "As seen in this example, when the query is an INSERT , UPDATE , DELETE , or MERGE command, the actual work of applying the table changes is done by a top-level Insert, Update, Delete, or Merge plan node. The plan nodes underneath this node perform the work of locating the old rows and/or computing the new data. So above, we see the same sort of bitmap table scan we've seen already, and its output is fed to an Update node that stores the updated rows. It's worth noting that although the data-modifying node can take a considerable amount of run time (here, it's consuming the lion's share of the time), the planner does not currently add anything to the cost estimates to account for that work. That's because the work to be done is the same for every correct query plan, so it doesn't affect planning decisions.", "/versions/20/sections/3/paragraphs/4": "When an UPDATE , DELETE , or MERGE command affects a partitioned table or inheritance hierarchy, the output might look like this:", "/versions/20/sections/3/paragraphs/5": "Merge joins also have measurement artifacts that can confuse the unwary. A merge join will stop reading one input if it's exhausted the other input and the next key value in the one input is greater than the last key value of the other input; in such a case there can be no more matches and so no need to scan the rest of the first input. This results in not reading all of one child, with results like those mentioned for LIMIT . Also, if the outer (first) child contains rows with duplicate key values, the inner (second) child is backed up and rescanned for the portion of its rows matching that key value. EXPLAIN ANALYZE counts these repeated emissions of the same inner rows as if they were real additional rows. When there are many outer duplicates, the reported actual row count for the inner child plan node can be significantly larger than the number of rows that are actually in the inner relation.", "/versions/20/sections/5/paragraphs/0": "Merge-join is done by joining the inner and outer tuples satisfying join clauses of the form ((= outerKey innerKey) ...). The join clause list is provided by the query planner and may contain more than one (= outerKey innerKey) clause (for composite sort key).", "/versions/20/sections/5/paragraphs/1": "However, the query executor needs to know whether an outer tuple is \"greater/smaller\" than an inner tuple so that it can \"synchronize\" the two relations. For example, consider the following relations:", "/versions/20/sections/5/paragraphs/3": "To continue the merge-join, the executor needs to scan both inner and outer relations till the matching tuples 5. It needs to know that currently inner tuple 3 is \"greater\" than outer tuple 1 and therefore it should scan the outer relation first to find a matching tuple and so on.", "/versions/20/sections/5/paragraphs/4": "Therefore, rather than directly executing the merge join clauses, we evaluate the left and right key expressions separately and then compare the columns one at a time (see MJCompare). The planner passes us enough information about the sort ordering of the inputs to allow us to determine how to make the comparison. We may use the appropriate btree comparison function, since Postgres' only notion of ordering is specified by btree opfamilies.", "/versions/20/tables/0/columns/0/label": "Text-format label", "/versions/20/tables/0/columns/1/label": "Structured node identity", "/versions/20/sections/4/blocks/0/paragraphs/0": "Example copied from the PostgreSQL 20devel manual; it was not executed for this collection.", "/versions/20/sections/4/blocks/0/paragraphs/1": "Another possible type of join is a merge join, illustrated here:"}, "fallback_fields": [], "source_language": "en", "original_snapshot_sha256": "8b2c705d030ed72c5a009c73626bd3e32caf5cea4162e85b1984f7670fecadd6"}, "evidence_kind": "source and documentation", "explain_names": ["Merge"], "partial_modes": [], "comparison_data": {"node_tag": "T_MergeJoin", "strategies": [], "text_names": ["Merge"], "initializer": "ExecInitMergeJoin", "partial_modes": [], "memory_mechanism": "unclassified", "parallel_callbacks": []}, "comparison_hash": "b17771ee4d48585afbaba91552e5eb00f05a4b6784aa491387217937a4a30511", "explain_prefixes": ["Parallel", "Async"], "runtime_verified": false, "source_inventory": {"explain": "src/backend/commands/explain.c", "executor": "src/backend/executor/execProcnode.c", "implementation": "src/backend/executor/nodeMergejoin.c"}, "parallel_callbacks": []}}}, "snapshot": {"facts": [{"label": "\u6838\u5fc3\u8282\u70b9\u6807\u7b7e", "value": "T_MergeJoin"}, {"label": "\u7ed3\u6784\u5316 EXPLAIN \u8282\u70b9\u7c7b\u578b", "value": "Merge Join"}, {"label": "\u8f93\u5165", "value": "\u6709\u5e8f\u7684\u5916\u4fa7\u548c\u5185\u4fa7\u5b50\u8ba1\u5212"}, {"label": "\u8f93\u51fa", "value": "\u6309\u6240\u9009\u8fde\u63a5\u7c7b\u578b\u751f\u6210\u7684\u8fde\u63a5\u5143\u7ec4"}, {"label": "\u6267\u884c\u5668\u521d\u59cb\u5316\u51fd\u6570", "value": "ExecInitMergeJoin"}, {"label": "\u5185\u5b58\u673a\u5236", "value": "unclassified"}], "memory": {"evidence": [{"url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "df6726b291493e06be7c43e5664bfb4251267eff66481eaf8e04969c39612b25", "archive_sha256": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}], "mechanism": "unclassified", "description": "\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002", "source_notes": []}, "tables": [{"key": "explain-labels", "rows": [{"label": "Merge", "identity": "Merge Join"}], "title": "\u672c\u6784\u5efa\u4e2d\u7684 EXPLAIN \u6807\u7b7e", "columns": [{"key": "label", "label": "\u6587\u672c\u683c\u5f0f\u6807\u7b7e"}, {"key": "identity", "label": "\u7ed3\u6784\u5316\u8282\u70b9\u6807\u8bc6"}]}], "related": [{"url": "/wiki/sql/explain/?v=18", "label": "EXPLAIN"}, {"url": "/docs/18/using-explain.html", "label": "\u4f7f\u7528 EXPLAIN"}, {"url": "/docs/18/parallel-plans.html", "label": "\u5e76\u884c\u8ba1\u5212"}, {"url": "/wiki/guc/enable_mergejoin/?v=18", "label": "enable_mergejoin"}], "release": {"ref": "PostgreSQL 18.6 source archive", "label": "18.6", "major": "18", "channel": "stable", "revision": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f", "source_url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "source_snapshot_utc": ""}, "sources": [{"url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "line": 1424, "path": "src/backend/commands/explain.c", "label": "src/backend/commands/explain.c:1424", "sha256": "34c86d6070224a0e981efef51f79101d6d505e5874f1684ace183034bab14bb4", "archive_sha256": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}, {"url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "line": 302, "path": "src/backend/executor/execProcnode.c", "label": "src/backend/executor/execProcnode.c:302", "sha256": "f8a06a3f539077249b20664b2812433db6d7bd12b2c0ca633525db43d06f112a", "archive_sha256": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}, {"url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "path": "src/backend/executor/nodeMergejoin.c", "label": "src/backend/executor/nodeMergejoin.c", "sha256": "df6726b291493e06be7c43e5664bfb4251267eff66481eaf8e04969c39612b25", "archive_sha256": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}, {"url": "https://ftp.postgresql.org/pub/source/v18.6/postgresql-18.6.tar.bz2", "path": "src/include/nodes/plannodes.h", "label": "src/include/nodes/plannodes.h", "sha256": "52422b327a8049fbbb20d8b96008a0fc0a6fafa60f7eff3c695d5b2e83830120", "archive_sha256": "555610c24d53e4316da5b7d3fc25c279d96856d5e0e23ee308c328c5fa881d9f"}, {"url": "https://pg.center/docs/18/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 18.6 \u00b7 using-explain", "sha256": "60040c30180093418a0affe56dd27dff9df2504b705b38039589e458bf5c31ed", "language": "en", "original_url": "/docs/18/using-explain.html#USING-EXPLAIN-BASICS"}, {"url": "https://pg.center/docs/18/using-explain.html#USING-EXPLAIN-ANALYZE", "path": "using-explain.html", "label": "PostgreSQL 18.6 \u00b7 using-explain", "sha256": "60040c30180093418a0affe56dd27dff9df2504b705b38039589e458bf5c31ed", "language": "en", "original_url": "/docs/18/using-explain.html#USING-EXPLAIN-ANALYZE"}, {"url": "https://pg.center/docs/18/using-explain.html#USING-EXPLAIN-CAVEATS", "path": "using-explain.html", "label": "PostgreSQL 18.6 \u00b7 using-explain", "sha256": "60040c30180093418a0affe56dd27dff9df2504b705b38039589e458bf5c31ed", "language": "en", "original_url": "/docs/18/using-explain.html#USING-EXPLAIN-CAVEATS"}], "node_tag": "T_MergeJoin", "sections": [{"title": "EXPLAIN \u540d\u79f0\u4e0e\u5c5e\u6027", "paragraphs": ["\u7ed3\u6784\u5316\u683c\u5f0f\u4f7f\u7528\u4e0a\u8ff0 Node Type\u3002\u6587\u672c\u683c\u5f0f\u540d\u79f0\u8fd8\u53ef\u80fd\u5305\u542b\u64cd\u4f5c\u3001\u7b56\u7565\u3001\u8fde\u63a5\u7c7b\u578b\u3001\u626b\u63cf\u65b9\u5411\u6216\u805a\u5408\u9636\u6bb5\u5c5e\u6027\u3002", "\u6b64\u6e90\u7801\u8bb0\u5f55\u7684\u6587\u672c\u540d\u79f0\uff1aMerge.", "\u5e76\u884c\u611f\u77e5\u4e0e\u5e76\u884c\u5b89\u5168\u662f\u4e0d\u540c\u7684\u8ba1\u5212\u5c5e\u6027\u3002\u5728\u5e76\u884c\u5de5\u4f5c\u8fdb\u7a0b\u5185\u8fd0\u884c\u7684\u8282\u70b9\u4e0d\u4e00\u5b9a\u662f\u5e76\u884c\u611f\u77e5\u8282\u70b9\u3002"]}, {"title": "\u5185\u5b58\u4e0e\u4e34\u65f6\u5b58\u50a8", "paragraphs": ["\u672c\u6b21\u62bd\u53d6\u4e0d\u4e3a\u6b64\u8282\u70b9\u8bbe\u5b9a\u7edf\u4e00\u7684\u5185\u5b58\u4e0a\u9650\u6216\u843d\u76d8\u7b56\u7565\u3002\u8bf7\u67e5\u770b\u540c\u4e00\u6784\u5efa\u7684\u5b9e\u73b0\u3001\u76f8\u5173\u8868\u8fbe\u5f0f\u6216\u63d0\u4f9b\u65b9\u3002"]}, {"title": "\u5e76\u884c\u6267\u884c\u4e0e\u8fd0\u884c\u4fe1\u606f\u91c7\u96c6", "paragraphs": ["\u4ee5\u4e0b\u6e90\u7801\u56de\u8c03\u53ef\u4ee5\u534f\u8c03\u6267\u884c\u6216\u6536\u96c6\u5de5\u4f5c\u8fdb\u7a0b\u7684\u6d4b\u91cf\u6570\u636e\u3002\u56de\u8c03\u5b58\u5728\u4e0d\u4ee3\u8868\u8be5\u8282\u70b9\u666e\u904d\u652f\u6301\u5171\u4eab\u5e76\u884c\u626b\u63cf\u6216\u5171\u4eab\u72b6\u6001\u3002", "\u6b64\u6784\u5efa\u7684\u56de\u8c03\uff1anone extracted from this node implementation."]}, {"title": "\u540c\u7248\u672c\u624b\u518c\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u8981\u6c42\u8f93\u5165\u6570\u636e\u6309\u8fde\u63a5\u952e\u6392\u5e8f\u3002\u5728\u8fd9\u4e2a\u4f8b\u5b50\u4e2d\uff0c\u4e24\u4e2a\u8f93\u5165\u90fd\u901a\u8fc7\u7d22\u5f15\u626b\u63cf\u6309\u6b63\u786e\u987a\u5e8f\u8bbf\u95ee\u884c\u800c\u5b8c\u6210\u6392\u5e8f\uff1b\u4e0d\u8fc7\u4e5f\u53ef\u4ee5\u91c7\u7528\u987a\u5e8f\u626b\u63cf\u518d\u6392\u5e8f\u7684\u65b9\u5f0f\u3002\uff08\u5bf9\u4e8e\u9700\u8981\u6392\u5e8f\u5f88\u591a\u884c\u7684\u60c5\u51b5\uff0c\u987a\u5e8f\u626b\u63cf\u52a0\u6392\u5e8f\u5f80\u5f80\u4f1a\u80dc\u8fc7\u7d22\u5f15\u626b\u63cf\uff0c\u56e0\u4e3a\u7d22\u5f15\u626b\u63cf\u9700\u8981\u975e\u987a\u5e8f\u78c1\u76d8\u8bbf\u95ee\u3002\uff09", "\u89c2\u5bdf\u5907\u9009\u8ba1\u5212\u7684\u4e00\u79cd\u65b9\u6cd5\uff0c\u662f\u5229\u7528 \u7b2c 19.7.1 \u8282 \u4e2d\u63cf\u8ff0\u7684\u542f\u7528/\u7981\u7528\u6807\u5fd7\uff0c\u5f3a\u8feb\u89c4\u5212\u5668\u5ffd\u7565\u5b83\u8ba4\u4e3a\u6700\u4fbf\u5b9c\u7684\u7b56\u7565\u3002\uff08\u8fd9\u662f\u4e2a\u7c97\u7cd9\u4f46\u6709\u7528\u7684\u5de5\u5177\u3002\u53e6\u89c1 \u7b2c 14.3 \u8282 \u3002\uff09\u4f8b\u5982\uff0c\u5982\u679c\u6211\u4eec\u5e76\u4e0d\u786e\u4fe1\u524d\u4e00\u4e2a\u793a\u4f8b\u4e2d\u5f52\u5e76\u8fde\u63a5\u771f\u7684\u662f\u6700\u4f73\u8fde\u63a5\u7c7b\u578b\uff0c\u53ef\u4ee5\u8bd5\u8bd5\uff1a", "\u8fd9\u8868\u660e\uff0c\u89c4\u5212\u5668\u8ba4\u4e3a\u5728\u8fd9\u4e2a\u573a\u666f\u4e0b\uff0c\u54c8\u5e0c\u8fde\u63a5\u7684\u4ee3\u4ef7\u51e0\u4e4e\u6bd4\u5f52\u5e76\u8fde\u63a5\u9ad8\u51fa 50%\u3002\u5f53\u7136\uff0c\u63a5\u4e0b\u6765\u7684\u95ee\u9898\u5c31\u662f\u5b83\u662f\u5426\u5224\u65ad\u6b63\u786e\u3002\u6211\u4eec\u53ef\u4ee5\u50cf \u4e0b\u6587 \u6240\u8ff0\uff0c\u4f7f\u7528 EXPLAIN ANALYZE \u6765\u7814\u7a76\u3002", "\u5982\u672c\u4f8b\u6240\u793a\uff0c\u67e5\u8be2\u4e3a INSERT\u3001UPDATE\u3001DELETE \u6216 MERGE \u547d\u4ee4\u65f6\uff0c\u5b9e\u9645\u5e94\u7528\u8868\u53d8\u66f4\u7684\u5de5\u4f5c\u7531\u9876\u5c42 Insert\u3001Update\u3001Delete \u6216 Merge \u8ba1\u5212\u8282\u70b9\u5b8c\u6210\u3002\u5176\u4e0b\u7684\u8ba1\u5212\u8282\u70b9\u8d1f\u8d23\u5b9a\u4f4d\u65e7\u884c\u548c\uff0f\u6216\u8ba1\u7b97\u65b0\u6570\u636e\u3002\u56e0\u6b64\uff0c\u4e0a\u4f8b\u4ecd\u91c7\u7528\u524d\u9762\u89c1\u8fc7\u7684\u4f4d\u56fe\u8868\u626b\u63cf\uff0c\u5176\u8f93\u51fa\u4f20\u7ed9 Update \u8282\u70b9\uff0c\u7531\u540e\u8005\u5b58\u50a8\u66f4\u65b0\u540e\u7684\u884c\u3002\u867d\u7136\u6570\u636e\u4fee\u6539\u8282\u70b9\u53ef\u80fd\u6d88\u8017\u76f8\u5f53\u591a\u7684\u8fd0\u884c\u65f6\u95f4\uff08\u672c\u4f8b\u4e2d\u5360\u4e86\u7edd\u5927\u90e8\u5206\uff09\uff0c\u4f46\u89c4\u5212\u5668\u76ee\u524d\u5e76\u672a\u5c06\u8fd9\u90e8\u5206\u5de5\u4f5c\u8ba1\u5165\u4ee3\u4ef7\u4f30\u7b97\u3002\u8fd9\u662f\u56e0\u4e3a\u4efb\u4f55\u6b63\u786e\u67e5\u8be2\u8ba1\u5212\u9700\u8981\u5b8c\u6210\u7684\u8fd9\u90e8\u5206\u5de5\u4f5c\u90fd\u76f8\u540c\uff0c\u56e0\u6b64\u4e0d\u4f1a\u5f71\u54cd\u89c4\u5212\u51b3\u7b56\u3002", "\u5f53 UPDATE \u3001 DELETE \u6216 MERGE \u547d\u4ee4\u5f71\u54cd\u5206\u533a\u8868\u6216\u7ee7\u627f\u5c42\u6b21\u65f6\uff0c\u8f93\u51fa\u53ef\u80fd\u50cf\u8fd9\u6837\uff1a", "\u5f52\u5e76\u8fde\u63a5\u7684\u6d4b\u91cf\u7ed3\u679c\u4e5f\u53ef\u80fd\u4ea7\u751f\u8bef\u5bfc\u3002\u82e5\u4e00\u4fa7\u8f93\u5165\u5df2\u8017\u5c3d\uff0c\u53e6\u4e00\u4fa7\u7684\u4e0b\u4e00\u4e2a\u952e\u503c\u53c8\u5927\u4e8e\u5df2\u8017\u5c3d\u8f93\u5165\u7684\u6700\u540e\u4e00\u4e2a\u952e\u503c\uff0c\u5c31\u4e0d\u4f1a\u518d\u6709\u5339\u914d\uff0c\u56e0\u6b64\u4f1a\u505c\u6b62\u8bfb\u53d6\u53e6\u4e00\u4fa7\u3002\u8fd9\u6837\u4fbf\u672a\u8bfb\u53d6\u8be5\u5b50\u8282\u70b9\u7684\u5168\u90e8\u884c\uff0c\u7c7b\u4f3c LIMIT \u7684\u60c5\u51b5\u3002\u53e6\u5916\uff0c\u5916\u4fa7\uff08\u7b2c\u4e00\u4e2a\uff09\u5b50\u8282\u70b9\u6709\u91cd\u590d\u952e\u503c\u65f6\uff0c\u5185\u4fa7\uff08\u7b2c\u4e8c\u4e2a\uff09\u5b50\u8282\u70b9\u4f1a\u56de\u9000\u5e76\u91cd\u65b0\u626b\u63cf\u5339\u914d\u8be5\u952e\u503c\u7684\u884c\u3002EXPLAIN ANALYZE \u4f1a\u5c06\u5185\u4fa7\u91cd\u590d\u8f93\u51fa\u7684\u884c\u8ba1\u4f5c\u989d\u5916\u7684\u771f\u5b9e\u884c\u3002\u56e0\u6b64\u5916\u4fa7\u91cd\u590d\u503c\u5f88\u591a\u65f6\uff0c\u5185\u4fa7\u8ba1\u5212\u8282\u70b9\u62a5\u544a\u7684\u5b9e\u9645\u884c\u6570\u53ef\u80fd\u663e\u8457\u8d85\u8fc7\u5185\u4fa7\u5173\u7cfb\u4e2d\u7684\u5b9e\u9645\u884c\u6570\u3002"]}, {"title": "\u672c\u7248\u624b\u518c\u4e2d\u7684\u793a\u4f8b", "blocks": [{"code": "EXPLAIN SELECT *\nFROM tenk1 t1, onek t2\nWHERE t1.unique1 < 100 AND t1.unique2 = t2.unique2;\n\n                                        QUERY PLAN\n------------------------------------------------------------------------------------------\n Merge Join  (cost=0.56..233.49 rows=10 width=488)\n   Merge Cond: (t1.unique2 = t2.unique2)\n   ->  Index Scan using tenk1_unique2 on tenk1 t1  (cost=0.29..643.28 rows=100 width=244)\n         Filter: (unique1 < 100)\n   ->  Index Scan using onek_unique2 on onek t2  (cost=0.28..166.28 rows=1000 width=244)", "source": {"url": "/docs/18/using-explain.html#USING-EXPLAIN-BASICS", "path": "using-explain.html", "label": "PostgreSQL 18.6 \u00b7 using-explain", "sha256": "60040c30180093418a0affe56dd27dff9df2504b705b38039589e458bf5c31ed"}, "paragraphs": ["\u793a\u4f8b\u6458\u81ea PostgreSQL 18.6 \u624b\u518c\uff1b\u672c\u767e\u79d1\u672a\u5b9e\u9645\u6267\u884c\u6b64\u793a\u4f8b\u3002", "\u53e6\u4e00\u79cd\u53ef\u80fd\u7684\u8fde\u63a5\u65b9\u5f0f\u662f\u5f52\u5e76\u8fde\u63a5\uff0c\u5982\u4e0b\u6240\u793a\uff1a"]}]}, {"title": "\u6267\u884c\u5668\u5b9e\u73b0\u8bf4\u660e", "paragraphs": ["\u5f52\u5e76\u8fde\u63a5\u5bf9\u6ee1\u8db3 ((= outerKey innerKey) ...) \u5f62\u5f0f\u8fde\u63a5\u6761\u4ef6\u7684\u5185\u5916\u4fa7\u5143\u7ec4\u6267\u884c\u8fde\u63a5\u3002\u8fde\u63a5\u6761\u4ef6\u5217\u8868\u7531\u67e5\u8be2\u89c4\u5212\u5668\u63d0\u4f9b\uff0c\u53ef\u4ee5\u5305\u542b\u591a\u4e2a (= outerKey innerKey) \u6761\u4ef6\uff0c\u4ee5\u652f\u6301\u590d\u5408\u6392\u5e8f\u952e\u3002", "\u4e0d\u8fc7\uff0c\u67e5\u8be2\u6267\u884c\u5668\u9700\u8981\u5224\u65ad\u5916\u4fa7\u5143\u7ec4\u662f\u5426\u201c\u5927\u4e8e\uff0f\u5c0f\u4e8e\u201d\u5185\u4fa7\u5143\u7ec4\uff0c\u4ee5\u4fbf\u201c\u540c\u6b65\u201d\u4e24\u4e2a\u5173\u7cfb\u3002\u4f8b\u5982\uff0c\u8003\u8651\u4ee5\u4e0b\u5173\u7cfb\uff1a", "outer: (0 ^1 1 2 5 5 5 6 6 7) current tuple: 1 inner: (1 ^3 5 5 5 5 6) current tuple: 3", "\u4e3a\u7ee7\u7eed\u5f52\u5e76\u8fde\u63a5\uff0c\u6267\u884c\u5668\u9700\u8981\u626b\u63cf\u5185\u5916\u4fa7\u5173\u7cfb\uff0c\u76f4\u5230\u627e\u5230\u5339\u914d\u7684\u5143\u7ec4 5\u3002\u5b83\u9700\u8981\u77e5\u9053\u5f53\u524d\u5185\u4fa7\u5143\u7ec4 3\u201c\u5927\u4e8e\u201d\u5916\u4fa7\u5143\u7ec4 1\uff0c\u56e0\u6b64\u5e94\u5148\u626b\u63cf\u5916\u4fa7\u5173\u7cfb\u4ee5\u5bfb\u627e\u5339\u914d\uff0c\u4f9d\u6b64\u7c7b\u63a8\u3002", "\u56e0\u6b64\uff0c\u4e0d\u76f4\u63a5\u6267\u884c\u5f52\u5e76\u8fde\u63a5\u6761\u4ef6\uff0c\u800c\u662f\u5206\u522b\u6c42\u503c\u5de6\u53f3\u952e\u8868\u8fbe\u5f0f\uff0c\u518d\u9010\u5217\u6bd4\u8f83\uff08\u53c2\u89c1 MJCompare\uff09\u3002\u89c4\u5212\u5668\u63d0\u4f9b\u8db3\u591f\u7684\u8f93\u5165\u6392\u5e8f\u4fe1\u606f\uff0c\u8ba9\u6267\u884c\u5668\u786e\u5b9a\u6bd4\u8f83\u65b9\u6cd5\u3002\u53ef\u4ee5\u4f7f\u7528\u76f8\u5e94\u7684 B-tree \u6bd4\u8f83\u51fd\u6570\uff0c\u56e0\u4e3a Postgres \u7684\u6392\u5e8f\u8bed\u4e49\u4ec5\u7531 B-tree \u64cd\u4f5c\u7b26\u5bb6\u65cf\u5b9a\u4e49\u3002"]}, {"code": "case T_MergeJoin:\n\t\t\tpname = \"Merge\";\t/* \"Join\" gets added by jointype switch */\n\t\t\tsname = \"Merge Join\";\n\t\t\tbreak;", "title": "\u6838\u5fc3\u6e90\u7801\u4e2d\u7684 EXPLAIN \u6807\u8bc6"}], "strategies": [], "description": ["\u4f7f\u7528\u5f52\u5e76\u6761\u4ef6\u8fde\u63a5\u6709\u5e8f\u8f93\u5165\u6d41\u3002"], "localization": {"status": "complete", "sources": [{"url": "/docs/18/using-explain.html", "method": "same-major semantic node", "sha256": "b8835ec9adbc70ec150667a6b5443f8d298222dc0cc8c2bd1abb1c1d64895904", "language": "zh", "matched_nodes": ["#USING-EXPLAIN/div[7]/p[51]", "#USING-EXPLAIN/div[7]/p[52]", "#USING-EXPLAIN/div[7]/p[54]", "#USING-EXPLAIN/div[8]/p[29]"]}], "language": "zh", "original_text": {"/versions/18/description/0": "Joins ordered input streams using merge clauses.", "/versions/18/facts/0/label": "Core node tag", "/versions/18/facts/1/label": "Structured EXPLAIN Node Type", "/versions/18/facts/2/label": "Inputs", "/versions/18/facts/2/value": "Ordered outer and inner child plans", "/versions/18/facts/3/label": "Output", "/versions/18/facts/3/value": "Joined tuples according to the selected join type", "/versions/18/facts/4/label": "Executor initializer", "/versions/18/facts/5/label": "Memory mechanism", "/versions/18/tables/0/title": "EXPLAIN labels in this source build", "/versions/18/related/1/label": "Using EXPLAIN", "/versions/18/related/2/label": "Parallel plans", "/versions/18/sections/0/title": "EXPLAIN names and attributes", "/versions/18/sections/1/title": "Memory and temporary storage", "/versions/18/sections/2/title": "Parallel execution and instrumentation", "/versions/18/sections/3/title": "Same-version manual discussion", "/versions/18/sections/4/title": "Examples from this manual build", "/versions/18/sections/5/title": "Executor implementation notes", "/versions/18/sections/6/title": "EXPLAIN identity in core source", "/versions/18/memory/description": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/18/sections/0/paragraphs/0": "Structured formats use the Node Type above. Text-format spellings can also include operation, strategy, join type, scan direction or aggregation-stage attributes.", "/versions/18/sections/0/paragraphs/1": "Text names recorded by this source: Merge.", "/versions/18/sections/0/paragraphs/2": "Parallel-aware and parallel-safe are different plan properties. A node running inside a parallel worker is not necessarily a parallel-aware node.", "/versions/18/sections/1/paragraphs/0": "This extraction does not assign a universal memory limit or spill policy to this node. Inspect the same-build implementation and its expressions or provider.", "/versions/18/sections/2/paragraphs/0": "The source callbacks below can coordinate execution or collect worker instrumentation. Their presence is not a blanket claim that this node supports a shared parallel scan or shared state.", "/versions/18/sections/2/paragraphs/1": "Callbacks in this build: none extracted from this node implementation.", "/versions/18/sections/3/paragraphs/0": "Merge join requires its input data to be sorted on the join keys. In this example each input is sorted by using an index scan to visit the rows in the correct order; but a sequential scan and sort could also be used. (Sequential-scan-and-sort frequently beats an index scan for sorting many rows, because of the nonsequential disk access required by the index scan.)", "/versions/18/sections/3/paragraphs/1": "One way to look at variant plans is to force the planner to disregard whatever strategy it thought was the cheapest, using the enable/disable flags described in Section 19.7.1 . (This is a crude tool, but useful. See also Section 14.3 .) For example, if we're unconvinced that merge join is the best join type for the previous example, we could try", "/versions/18/sections/3/paragraphs/2": "which shows that the planner thinks that hash join would be nearly 50% more expensive than merge join for this case. Of course, the next question is whether it's right about that. We can investigate that using EXPLAIN ANALYZE , as discussed below .", "/versions/18/sections/3/paragraphs/3": "As seen in this example, when the query is an INSERT , UPDATE , DELETE , or MERGE command, the actual work of applying the table changes is done by a top-level Insert, Update, Delete, or Merge plan node. The plan nodes underneath this node perform the work of locating the old rows and/or computing the new data. So above, we see the same sort of bitmap table scan we've seen already, and its output is fed to an Update node that stores the updated rows. It's worth noting that although the data-modifying node can take a considerable amount of run time (here, it's consuming the lion's share of the time), the planner does not currently add anything to the cost estimates to account for that work. That's because the work to be done is the same for every correct query plan, so it doesn't affect planning decisions.", "/versions/18/sections/3/paragraphs/4": "When an UPDATE , DELETE , or MERGE command affects a partitioned table or inheritance hierarchy, the output might look like this:", "/versions/18/sections/3/paragraphs/5": "Merge joins also have measurement artifacts that can confuse the unwary. A merge join will stop reading one input if it's exhausted the other input and the next key value in the one input is greater than the last key value of the other input; in such a case there can be no more matches and so no need to scan the rest of the first input. This results in not reading all of one child, with results like those mentioned for LIMIT . Also, if the outer (first) child contains rows with duplicate key values, the inner (second) child is backed up and rescanned for the portion of its rows matching that key value. EXPLAIN ANALYZE counts these repeated emissions of the same inner rows as if they were real additional rows. When there are many outer duplicates, the reported actual row count for the inner child plan node can be significantly larger than the number of rows that are actually in the inner relation.", "/versions/18/sections/5/paragraphs/0": "Merge-join is done by joining the inner and outer tuples satisfying join clauses of the form ((= outerKey innerKey) ...). The join clause list is provided by the query planner and may contain more than one (= outerKey innerKey) clause (for composite sort key).", "/versions/18/sections/5/paragraphs/1": "However, the query executor needs to know whether an outer tuple is \"greater/smaller\" than an inner tuple so that it can \"synchronize\" the two relations. For example, consider the following relations:", "/versions/18/sections/5/paragraphs/3": "To continue the merge-join, the executor needs to scan both inner and outer relations till the matching tuples 5. It needs to know that currently inner tuple 3 is \"greater\" than outer tuple 1 and therefore it should scan the outer relation first to find a matching tuple and so on.", "/versions/18/sections/5/paragraphs/4": "Therefore, rather than directly executing the merge join clauses, we evaluate the left and right key expressions separately and then compare the columns one at a time (see MJCompare). The planner passes us enough information about the sort ordering of the inputs to allow us to determine how to make the comparison. We may use the appropriate btree comparison function, since Postgres' only notion of ordering is specified by btree opfamilies.", "/versions/18/tables/0/columns/0/label": "Text-format label", "/versions/18/tables/0/columns/1/label": "Structured node identity", "/versions/18/sections/4/blocks/0/paragraphs/0": "Example copied from the PostgreSQL 18.6 manual; it was not executed for this collection.", "/versions/18/sections/4/blocks/0/paragraphs/1": "Another possible type of join is a merge join, illustrated here:"}, "fallback_fields": [], "source_language": "en", "original_snapshot_sha256": "36b750b49891ade23131d9581b03e3cc836daa7d11c125d079e38438d978badd"}, "evidence_kind": "source and documentation", "explain_names": ["Merge"], "partial_modes": [], "comparison_data": {"node_tag": "T_MergeJoin", "strategies": [], "text_names": ["Merge"], "initializer": "ExecInitMergeJoin", "partial_modes": [], "memory_mechanism": "unclassified", "parallel_callbacks": []}, "comparison_hash": "b17771ee4d48585afbaba91552e5eb00f05a4b6784aa491387217937a4a30511", "explain_prefixes": ["Parallel", "Async"], "runtime_verified": false, "source_inventory": {"explain": "src/backend/commands/explain.c", "executor": "src/backend/executor/execProcnode.c", "implementation": "src/backend/executor/nodeMergejoin.c"}, "parallel_callbacks": []}, "comparison": {"left": "17", "right": "18", "status": "unchanged", "diff": ""}}