explain.c 7.9 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.55 2000/03/14 23:06:12 thomas 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
		case T_Noname:
			pname = "Noname Scan";
181
			break;
182 183 184
		case T_Material:
			pname = "Materialize";
			break;
185 186 187 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;
		case T_Hash:
			pname = "Hash";
			break;
200 201 202
		case T_TidScan:
			pname = "Tid Scan";
			break;
203
		default:
204
			pname = "???";
205
			break;
206 207 208 209 210
	}

	appendStringInfo(str, pname);
	switch (nodeTag(plan))
	{
211
		case T_IndexScan:
212 213
			if (ScanDirectionIsBackward(((IndexScan *)plan)->indxorderdir))
				appendStringInfo(str, " Backward");
214
			appendStringInfo(str, " using ");
V
Vadim B. Mikheev 已提交
215
			i = 0;
B
Bruce Momjian 已提交
216
			foreach(l, ((IndexScan *) plan)->indxid)
V
Vadim B. Mikheev 已提交
217
			{
218 219
				relation = RelationIdGetRelation(lfirsti(l));
				Assert(relation);
220 221
				appendStringInfo(str, "%s%s",
								 (++i > 1) ? ", " : "",
222
								 stringStringInfo(RelationGetRelationName(relation)));
223 224
				/* drop relcache refcount from RelationIdGetRelation */
				RelationDecrementReferenceCount(relation);
V
Vadim B. Mikheev 已提交
225
			}
226
			/* FALL THRU */
227
		case T_SeqScan:
228
		case T_TidScan:
229 230 231 232
			if (((Scan *) plan)->scanrelid > 0)
			{
				RangeTblEntry *rte = nth(((Scan *) plan)->scanrelid - 1, es->rtable);

233 234
				appendStringInfo(str, " on %s",
								 stringStringInfo(rte->relname));
235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
				if (rte->ref != NULL)
				{
					if ((strcmp(rte->ref->relname, rte->relname) != 0)
						|| (length(rte->ref->attrs) > 0))
					{
						appendStringInfo(str, " %s",
										 stringStringInfo(rte->ref->relname));

						if (length(rte->ref->attrs) > 0)
						{
							List *c;
							int firstEntry = true;

							appendStringInfo(str, " (");
							foreach (c, rte->ref->attrs)
							{
								if (! firstEntry)
								{
									appendStringInfo(str, ", ");
									firstEntry = false;
								}
								appendStringInfo(str, "%s", strVal(lfirst(c)));
							}
							appendStringInfo(str, ")");
						}
					}
				}
262 263
			}
			break;
264 265
		default:
			break;
266 267 268
	}
	if (es->printCost)
	{
269 270 271
		appendStringInfo(str, "  (cost=%.2f..%.2f rows=%.0f width=%d)",
						 plan->startup_cost, plan->total_cost,
						 plan->plan_rows, plan->plan_width);
272
	}
273
	appendStringInfo(str, "\n");
274

V
Vadim B. Mikheev 已提交
275 276 277
	/* initPlan-s */
	if (plan->initPlan)
	{
278 279 280
		List	   *saved_rtable = es->rtable;
		List	   *lst;

B
Bruce Momjian 已提交
281
		for (i = 0; i < indent; i++)
V
Vadim B. Mikheev 已提交
282 283
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  InitPlan\n");
284
		foreach(lst, plan->initPlan)
V
Vadim B. Mikheev 已提交
285
		{
286
			es->rtable = ((SubPlan *) lfirst(lst))->rtable;
V
Vadim B. Mikheev 已提交
287 288 289
			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
			appendStringInfo(str, "    ->  ");
B
Bruce Momjian 已提交
290
			explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, indent + 2, es);
V
Vadim B. Mikheev 已提交
291 292 293
		}
		es->rtable = saved_rtable;
	}
294 295 296 297 298 299

	/* lefttree */
	if (outerPlan(plan))
	{
		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
V
Vadim B. Mikheev 已提交
300 301
		appendStringInfo(str, "  ->  ");
		explain_outNode(str, outerPlan(plan), indent + 3, es);
302
	}
303 304 305 306 307 308

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

V
Vadim B. Mikheev 已提交
313 314 315
	/* subPlan-s */
	if (plan->subPlan)
	{
316 317 318
		List	   *saved_rtable = es->rtable;
		List	   *lst;

V
Vadim B. Mikheev 已提交
319 320 321
		for (i = 0; i < indent; i++)
			appendStringInfo(str, "  ");
		appendStringInfo(str, "  SubPlan\n");
322
		foreach(lst, plan->subPlan)
V
Vadim B. Mikheev 已提交
323
		{
324
			es->rtable = ((SubPlan *) lfirst(lst))->rtable;
V
Vadim B. Mikheev 已提交
325 326 327
			for (i = 0; i < indent; i++)
				appendStringInfo(str, "  ");
			appendStringInfo(str, "    ->  ");
328
			explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, indent + 4, es);
V
Vadim B. Mikheev 已提交
329 330
		}
		es->rtable = saved_rtable;
331
	}
332 333 334 335 336 337

	if (nodeTag(plan) == T_Append)
	{
		List	   *saved_rtable = es->rtable;
		List	   *lst;
		int			whichplan = 0;
338
		Append	   *appendplan = (Append *) plan;
339 340 341

		foreach(lst, appendplan->appendplans)
		{
342
			Plan	   *subnode = (Plan *) lfirst(lst);
343 344 345

			if (appendplan->inheritrelid > 0)
			{
346
				RangeTblEntry *rtentry;
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364

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

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

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

			whichplan++;
		}
		es->rtable = saved_rtable;
	}
365 366
}

367
static char *
368
Explain_PlanToString(Plan *plan, ExplainState *es)
369
{
B
Bruce Momjian 已提交
370
	StringInfoData str;
371

372 373 374 375 376
	/* see stringinfo.h for an explanation of this maneuver */
	initStringInfo(&str);
	if (plan != NULL)
		explain_outNode(&str, plan, 0, es);
	return str.data;
377
}