explain.c 8.6 KB
Newer Older
M
 
Marc G. Fournier 已提交
1
/*
2
 * explain.c
3
 *	  Explain the query execution plan
4
 *
B
Add:  
Bruce Momjian 已提交
5 6
 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
 * Portions Copyright (c) 1994-5, Regents of the University of California
7
 *
8
 * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.60 2000/10/05 19:11:26 tgl Exp $
9 10
 *
 */
11

12
#include "postgres.h"
M
Marc G. Fournier 已提交
13

14
#include "commands/explain.h"
B
Bruce Momjian 已提交
15 16
#include "lib/stringinfo.h"
#include "nodes/print.h"
17
#include "optimizer/planner.h"
B
Bruce Momjian 已提交
18
#include "parser/parsetree.h"
19
#include "rewrite/rewriteHandler.h"
B
Bruce Momjian 已提交
20
#include "utils/relcache.h"
21

22 23 24
typedef struct ExplainState
{
	/* options */
25
	bool		printCost;		/* print cost */
26
	bool		printNodes;		/* do nodeToString() instead */
27
	/* other states */
28
	List	   *rtable;			/* range table */
29
} ExplainState;
30

31
static char *Explain_PlanToString(Plan *plan, ExplainState *es);
B
Bruce Momjian 已提交
32 33
static void ExplainOneQuery(Query *query, bool verbose, CommandDest dest);

34 35 36
/* Convert a null string pointer into "<>" */
#define stringStringInfo(s) (((s) == NULL) ? "<>" : (s))

37 38 39

/*
 * ExplainQuery -
40
 *	  print out the execution plan for a given query
41 42 43
 *
 */
void
44
ExplainQuery(Query *query, bool verbose, CommandDest dest)
45
{
B
Bruce Momjian 已提交
46 47
	List	   *rewritten;
	List	   *l;
48

49
	/* rewriter and planner may not work in aborted state? */
50 51 52 53
	if (IsAbortedTransactionBlockState())
	{
		elog(NOTICE, "(transaction aborted): %s",
			 "queries ignored until END");
54 55
		return;
	}
56

57 58 59 60
	/* rewriter and planner will not cope with utility statements */
	if (query->commandType == CMD_UTILITY)
	{
		elog(NOTICE, "Utility statements have no plan structure");
61 62
		return;
	}
63

B
Bruce Momjian 已提交
64 65 66 67 68 69
	/* Rewrite through rule system */
	rewritten = QueryRewrite(query);

	/* In the case of an INSTEAD NOTHING, tell at least that */
	if (rewritten == NIL)
	{
70
		elog(NOTICE, "Query rewrites to nothing");
B
Bruce Momjian 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
		return;
	}

	/* Explain every plan */
	foreach(l, rewritten)
		ExplainOneQuery(lfirst(l), verbose, dest);
}

/*
 * ExplainOneQuery -
 *	  print out the execution plan for one query
 *
 */
static void
ExplainOneQuery(Query *query, bool verbose, CommandDest dest)
{
87
	char	   *s;
B
Bruce Momjian 已提交
88 89 90
	Plan	   *plan;
	ExplainState *es;

91
	/* plan the query */
92
	plan = planner(query);
93

94 95 96
	/* pg_plan could have failed */
	if (plan == NULL)
		return;
B
Bruce Momjian 已提交
97

B
Bruce Momjian 已提交
98
	es = (ExplainState *) palloc(sizeof(ExplainState));
B
Bruce Momjian 已提交
99
	MemSet(es, 0, sizeof(ExplainState));
B
Bruce Momjian 已提交
100

101
	es->printCost = true;		/* default */
102

103 104
	if (verbose)
		es->printNodes = true;
B
Bruce Momjian 已提交
105

106 107 108
	es->rtable = query->rtable;

	if (es->printNodes)
109
	{
110
		s = nodeToString(plan);
111 112
		if (s)
		{
113
			elog(NOTICE, "QUERY DUMP:\n\n%s", s);
114 115 116
			pfree(s);
		}
	}
117

118 119
	if (es->printCost)
	{
120 121
		s = Explain_PlanToString(plan, es);
		if (s)
122
		{
123
			elog(NOTICE, "QUERY PLAN:\n\n%s", s);
124
			pfree(s);
125
		}
B
Bruce Momjian 已提交
126
	}
127

128
	if (es->printNodes)
129
		pprint(plan);			/* display in postmaster log file */
130

B
Bruce Momjian 已提交
131
	pfree(es);
132 133 134 135 136 137 138 139
}

/*****************************************************************************
 *
 *****************************************************************************/

/*
 * explain_outNode -
140
 *	  converts a Node into ascii string and append it to 'str'
141 142
 */
static void
143
explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
144
{
B
Bruce Momjian 已提交
145
	List	   *l;
146
	Relation	relation;
B
Bruce Momjian 已提交
147 148
	char	   *pname;
	int			i;
149 150 151 152 153 154 155 156 157

	if (plan == NULL)
	{
		appendStringInfo(str, "\n");
		return;
	}

	switch (nodeTag(plan))
	{
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
		case T_Result:
			pname = "Result";
			break;
		case T_Append:
			pname = "Append";
			break;
		case T_NestLoop:
			pname = "Nested Loop";
			break;
		case T_MergeJoin:
			pname = "Merge Join";
			break;
		case T_HashJoin:
			pname = "Hash Join";
			break;
		case T_SeqScan:
			pname = "Seq Scan";
			break;
		case T_IndexScan:
			pname = "Index Scan";
			break;
179 180 181 182 183 184
		case T_TidScan:
			pname = "Tid Scan";
			break;
		case T_SubqueryScan:
			pname = "Subquery Scan";
			break;
185 186 187
		case T_Material:
			pname = "Materialize";
			break;
188 189 190 191 192 193 194 195 196 197 198 199
		case T_Sort:
			pname = "Sort";
			break;
		case T_Group:
			pname = "Group";
			break;
		case T_Agg:
			pname = "Aggregate";
			break;
		case T_Unique:
			pname = "Unique";
			break;
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
		case T_SetOp:
			switch (((SetOp *) plan)->cmd)
			{
				case SETOPCMD_INTERSECT:
					pname = "SetOp Intersect";
					break;
				case SETOPCMD_INTERSECT_ALL:
					pname = "SetOp Intersect All";
					break;
				case SETOPCMD_EXCEPT:
					pname = "SetOp Except";
					break;
				case SETOPCMD_EXCEPT_ALL:
					pname = "SetOp Except All";
					break;
				default:
					pname = "SetOp ???";
					break;
			}
			break;
220 221 222 223
		case T_Hash:
			pname = "Hash";
			break;
		default:
224
			pname = "???";
225
			break;
226 227 228 229 230
	}

	appendStringInfo(str, pname);
	switch (nodeTag(plan))
	{
231
		case T_IndexScan:
232
			if (ScanDirectionIsBackward(((IndexScan *) plan)->indxorderdir))
233
				appendStringInfo(str, " Backward");
234
			appendStringInfo(str, " using ");
V
Vadim B. Mikheev 已提交
235
			i = 0;
B
Bruce Momjian 已提交
236
			foreach(l, ((IndexScan *) plan)->indxid)
V
Vadim B. Mikheev 已提交
237
			{
238 239
				relation = RelationIdGetRelation(lfirsti(l));
				Assert(relation);
240 241
				appendStringInfo(str, "%s%s",
								 (++i > 1) ? ", " : "",
242
					stringStringInfo(RelationGetRelationName(relation)));
243 244
				/* drop relcache refcount from RelationIdGetRelation */
				RelationDecrementReferenceCount(relation);
V
Vadim B. Mikheev 已提交
245
			}
246
			/* FALL THRU */
247
		case T_SeqScan:
248
		case T_TidScan:
249 250
			if (((Scan *) plan)->scanrelid > 0)
			{
251 252 253 254 255
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);

				/* Assume it's on a real relation */
				Assert(rte->relname);
256

257 258
				appendStringInfo(str, " on %s",
								 stringStringInfo(rte->relname));
259 260 261 262 263 264 265 266 267 268 269 270 271
				if (strcmp(rte->eref->relname, rte->relname) != 0)
					appendStringInfo(str, " %s",
									 stringStringInfo(rte->eref->relname));
			}
			break;
		case T_SubqueryScan:
			if (((Scan *) plan)->scanrelid > 0)
			{
				RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
											  es->rtable);

				appendStringInfo(str, " %s",
								 stringStringInfo(rte->eref->relname));
272 273
			}
			break;
274 275
		default:
			break;
276 277 278
	}
	if (es->printCost)
	{
279 280 281
		appendStringInfo(str, "  (cost=%.2f..%.2f rows=%.0f width=%d)",
						 plan->startup_cost, plan->total_cost,
						 plan->plan_rows, plan->plan_width);
282
	}
283
	appendStringInfo(str, "\n");
284

V
Vadim B. Mikheev 已提交
285 286 287
	/* initPlan-s */
	if (plan->initPlan)
	{
288 289 290
		List	   *saved_rtable = es->rtable;
		List	   *lst;

B
Bruce Momjian 已提交
291
		for (i = 0; i < indent; i++)
V
Vadim B. Mikheev 已提交
292 293
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  InitPlan\n");
294
		foreach(lst, plan->initPlan)
V
Vadim B. Mikheev 已提交
295
		{
296
			es->rtable = ((SubPlan *) lfirst(lst))->rtable;
V
Vadim B. Mikheev 已提交
297 298 299
			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
			appendStringInfo(str, "    ->  ");
300 301
			explain_outNode(str, ((SubPlan *) lfirst(lst))->plan,
							indent + 4, es);
V
Vadim B. Mikheev 已提交
302 303 304
		}
		es->rtable = saved_rtable;
	}
305 306 307 308 309 310

	/* lefttree */
	if (outerPlan(plan))
	{
		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
V
Vadim B. Mikheev 已提交
311 312
		appendStringInfo(str, "  ->  ");
		explain_outNode(str, outerPlan(plan), indent + 3, es);
313
	}
314 315 316 317 318 319

	/* righttree */
	if (innerPlan(plan))
	{
		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
V
Vadim B. Mikheev 已提交
320 321 322
		appendStringInfo(str, "  ->  ");
		explain_outNode(str, innerPlan(plan), indent + 3, es);
	}
323

324
	if (IsA(plan, Append))
325
	{
326
		Append	   *appendplan = (Append *) plan;
327 328
		List	   *saved_rtable = es->rtable;
		int			whichplan = 0;
329
		List	   *lst;
330 331 332

		foreach(lst, appendplan->appendplans)
		{
333
			Plan	   *subnode = (Plan *) lfirst(lst);
334 335 336

			if (appendplan->inheritrelid > 0)
			{
337
				RangeTblEntry *rtentry;
338 339 340 341 342 343 344 345

				rtentry = nth(whichplan, appendplan->inheritrtable);
				Assert(rtentry != NULL);
				rt_store(appendplan->inheritrelid, es->rtable, rtentry);
			}

			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
346
			appendStringInfo(str, "  ->  ");
347

348
			explain_outNode(str, subnode, indent + 3, es);
349 350 351 352 353

			whichplan++;
		}
		es->rtable = saved_rtable;
	}
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394

	if (IsA(plan, SubqueryScan))
	{
		SubqueryScan *subqueryscan = (SubqueryScan *) plan;
		Plan	   *subnode = subqueryscan->subplan;
		RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid,
									  es->rtable);
		List	   *saved_rtable = es->rtable;

		Assert(rte->subquery != NULL);
		es->rtable = rte->subquery->rtable;

		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  ->  ");

		explain_outNode(str, subnode, indent + 3, es);

		es->rtable = saved_rtable;
	}

	/* subPlan-s */
	if (plan->subPlan)
	{
		List	   *saved_rtable = es->rtable;
		List	   *lst;

		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  SubPlan\n");
		foreach(lst, plan->subPlan)
		{
			es->rtable = ((SubPlan *) lfirst(lst))->rtable;
			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
			appendStringInfo(str, "    ->  ");
			explain_outNode(str, ((SubPlan *) lfirst(lst))->plan,
							indent + 4, es);
		}
		es->rtable = saved_rtable;
	}
395 396
}

397
static char *
398
Explain_PlanToString(Plan *plan, ExplainState *es)
399
{
B
Bruce Momjian 已提交
400
	StringInfoData str;
401

402 403 404 405 406
	/* see stringinfo.h for an explanation of this maneuver */
	initStringInfo(&str);
	if (plan != NULL)
		explain_outNode(&str, plan, 0, es);
	return str.data;
407
}