36
36
#include "nodes/nodes.h"
37
37
#include "nodes/parsenodes.h"
38
38
#include "storage/bufmgr.h"
39
+ #include "utils/builtins.h"
39
40
#include "utils/lsyscache.h"
40
41
#include "utils/guc.h"
41
42
@@ -49,6 +50,238 @@ static double online_analyze_scale_factor = 0.1;
49
50
static int online_analyze_threshold = 50 ;
50
51
static double online_analyze_min_interval = 10000 ;
51
52
53
+ typedef enum
54
+ {
55
+ OATT_ALL = 0x03 ,
56
+ OATT_PERSISTENT = 0x01 ,
57
+ OATT_TEMPORARY = 0x02 ,
58
+ OATT_NONE = 0x00
59
+ } OnlyneAnalyzeTableType ;
60
+
61
+ static const struct config_enum_entry online_analyze_table_type_options [] =
62
+ {
63
+ {"all" , OATT_ALL , false},
64
+ {"persistent" , OATT_PERSISTENT , false},
65
+ {"temporary" , OATT_TEMPORARY , false},
66
+ {"none" , OATT_NONE , false},
67
+ {NULL , 0 , false},
68
+ };
69
+
70
+ static int online_analyze_table_type = (int )OATT_ALL ;
71
+
72
+ typedef struct TableList {
73
+ int nTables ;
74
+ Oid * tables ;
75
+ char * tableStr ;
76
+ } TableList ;
77
+
78
+ static TableList excludeTables = {0 , NULL , NULL };
79
+ static TableList includeTables = {0 , NULL , NULL };
80
+
81
+ static int
82
+ oid_cmp (const void * a , const void * b )
83
+ {
84
+ if (* (Oid * )a == * (Oid * )b )
85
+ return 0 ;
86
+ return (* (Oid * )a > * (Oid * )b ) ? 1 : -1 ;
87
+ }
88
+
89
+ static const char *
90
+ tableListAssign (const char * newval , bool doit , TableList * tbl )
91
+ {
92
+ char * rawname ;
93
+ List * namelist ;
94
+ ListCell * l ;
95
+ Oid * newOids = NULL ;
96
+ int nOids = 0 ,
97
+ i = 0 ;
98
+
99
+ rawname = pstrdup (newval );
100
+
101
+ if (!SplitIdentifierString (rawname , ',' , & namelist ))
102
+ goto cleanup ;
103
+
104
+ if (doit )
105
+ {
106
+ nOids = list_length (namelist );
107
+ newOids = malloc (sizeof (Oid ) * (nOids + 1 ));
108
+ if (!newOids )
109
+ elog (ERROR ,"could not allocate %d bytes" , (int )(sizeof (Oid ) * (nOids + 1 )));
110
+ }
111
+
112
+ foreach (l , namelist )
113
+ {
114
+ char * curname = (char * ) lfirst (l );
115
+ Oid relOid = RangeVarGetRelid (makeRangeVarFromNameList (stringToQualifiedNameList (curname )), true);
116
+
117
+ if (relOid == InvalidOid )
118
+ {
119
+ #if PG_VERSION_NUM >= 90100
120
+ if (doit == false)
121
+ #endif
122
+ elog (WARNING ,"'%s' does not exist" , curname );
123
+ continue ;
124
+ }
125
+ else if ( get_rel_relkind (relOid ) != RELKIND_RELATION )
126
+ {
127
+ #if PG_VERSION_NUM >= 90100
128
+ if (doit == false)
129
+ #endif
130
+ elog (WARNING ,"'%s' is not an table" , curname );
131
+ continue ;
132
+ }
133
+ else if (doit )
134
+ {
135
+ newOids [i ++ ] = relOid ;
136
+ }
137
+ }
138
+
139
+ if (doit )
140
+ {
141
+ tbl -> nTables = i ;
142
+ if (tbl -> tables )
143
+ free (tbl -> tables );
144
+ tbl -> tables = newOids ;
145
+ if (tbl -> nTables > 1 )
146
+ qsort (tbl -> tables , tbl -> nTables , sizeof (tbl -> tables [0 ]), oid_cmp );
147
+ }
148
+
149
+ pfree (rawname );
150
+ list_free (namelist );
151
+
152
+ return newval ;
153
+
154
+ cleanup :
155
+ if (newOids )
156
+ free (newOids );
157
+ pfree (rawname );
158
+ list_free (namelist );
159
+ return NULL ;
160
+ }
161
+
162
+ #if PG_VERSION_NUM >= 90100
163
+ static bool
164
+ excludeTablesCheck (char * * newval , void * * extra , GucSource source )
165
+ {
166
+ char * val ;
167
+
168
+ val = (char * )tableListAssign (* newval , false, & excludeTables );
169
+
170
+ if (val )
171
+ {
172
+ * newval = val ;
173
+ return true;
174
+ }
175
+
176
+ return false;
177
+ }
178
+
179
+ static void
180
+ excludeTablesAssign (const char * newval , void * extra )
181
+ {
182
+ tableListAssign (newval , true, & excludeTables );
183
+ }
184
+
185
+ static bool
186
+ includeTablesCheck (char * * newval , void * * extra , GucSource source )
187
+ {
188
+ char * val ;
189
+
190
+ val = (char * )tableListAssign (* newval , false, & includeTables );
191
+
192
+ if (val )
193
+ {
194
+ * newval = val ;
195
+ return true;
196
+ }
197
+
198
+ return false;
199
+ }
200
+
201
+ static void
202
+ includeTablesAssign (const char * newval , void * extra )
203
+ {
204
+ tableListAssign (newval , true, & excludeTables );
205
+ }
206
+
207
+ #else /* PG_VERSION_NUM < 90100 */
208
+
209
+ static const char *
210
+ excludeTablesAssign (const char * newval , bool doit , GucSource source )
211
+ {
212
+ return tableListAssign (newval , doit , & excludeTables );
213
+ }
214
+
215
+ static const char *
216
+ includeTablesAssign (const char * newval , bool doit , GucSource source )
217
+ {
218
+ return tableListAssign (newval , doit , & includeTables );
219
+ }
220
+
221
+ #endif
222
+
223
+ static const char *
224
+ tableListShow (TableList * tbl )
225
+ {
226
+ char * val , * ptr ;
227
+ int i ,
228
+ len ;
229
+
230
+ len = 1 /* \0 */ + tbl -> nTables * (2 * NAMEDATALEN + 2 /* ', ' */ + 1 /* . */ );
231
+ ptr = val = palloc (len );
232
+ * ptr = '\0' ;
233
+ for (i = 0 ; i < tbl -> nTables ; i ++ )
234
+ {
235
+ char * relname = get_rel_name (tbl -> tables [i ]);
236
+ Oid nspOid = get_rel_namespace (tbl -> tables [i ]);
237
+ char * nspname = get_namespace_name (nspOid );
238
+
239
+ if ( relname == NULL || nspOid == InvalidOid || nspname == NULL )
240
+ continue ;
241
+
242
+ ptr += snprintf (ptr , len - (ptr - val ), "%s%s.%s" ,
243
+ (i == 0 ) ? "" : ", " ,
244
+ nspname , relname );
245
+ }
246
+
247
+ return val ;
248
+ }
249
+
250
+ static const char *
251
+ excludeTablesShow (void )
252
+ {
253
+ return tableListShow (& excludeTables );
254
+ }
255
+
256
+ static const char *
257
+ includeTablesShow (void )
258
+ {
259
+ return tableListShow (& includeTables );
260
+ }
261
+
262
+ static bool
263
+ matchOid (TableList * tbl , Oid oid )
264
+ {
265
+ Oid * StopLow = tbl -> tables ,
266
+ * StopHigh = tbl -> tables + tbl -> nTables ,
267
+ * StopMiddle ;
268
+
269
+ /* Loop invariant: StopLow <= val < StopHigh */
270
+ while (StopLow < StopHigh )
271
+ {
272
+ StopMiddle = StopLow + ((StopHigh - StopLow ) >> 1 );
273
+
274
+ if (* StopMiddle == oid )
275
+ return true;
276
+ else if (* StopMiddle < oid )
277
+ StopLow = StopMiddle + 1 ;
278
+ else
279
+ StopHigh = StopMiddle ;
280
+ }
281
+
282
+ return false;
283
+ }
284
+
52
285
static ExecutorEnd_hook_type oldhook = NULL ;
53
286
54
287
static void
@@ -84,6 +317,42 @@ makeAnalyze(Oid relOid, CmdType operation, uint32 naffected)
84
317
VacuumStmt vacstmt ;
85
318
TimestampTz startStamp , endStamp ;
86
319
320
+ /*
321
+ * includeTables overwrites excludeTables
322
+ */
323
+ switch (online_analyze_table_type )
324
+ {
325
+ case OATT_ALL :
326
+ if (matchOid (& excludeTables , relOid ) == true && matchOid (& includeTables , relOid ) == false)
327
+ return ;
328
+ break ;
329
+ case OATT_NONE :
330
+ if (matchOid (& includeTables , relOid ) == false)
331
+ return ;
332
+ break ;
333
+ case OATT_TEMPORARY :
334
+ case OATT_PERSISTENT :
335
+ default :
336
+ {
337
+ Relation rel ;
338
+ OnlyneAnalyzeTableType reltype ;
339
+
340
+ rel = RelationIdGetRelation (relOid );
341
+ reltype = (rel -> rd_istemp || rel -> rd_islocaltemp ) ? OATT_TEMPORARY : OATT_PERSISTENT ;
342
+ RelationClose (rel );
343
+
344
+ /*
345
+ * skip analyze if relation's type doesn't not match online_analyze_table_type
346
+ */
347
+ if ((online_analyze_table_type & reltype ) == 0 || matchOid (& excludeTables , relOid ) == true)
348
+ {
349
+ if (matchOid (& includeTables , relOid ) == false)
350
+ return ;
351
+ }
352
+ }
353
+ break ;
354
+ }
355
+
87
356
vacstmt .type = T_VacuumStmt ;
88
357
vacstmt .freeze_min_age = -1 ;
89
358
vacstmt .freeze_table_age = -1 ; /* ??? */
@@ -116,7 +385,8 @@ makeAnalyze(Oid relOid, CmdType operation, uint32 naffected)
116
385
117
386
endStamp = GetCurrentTimestamp ();
118
387
TimestampDifference (startStamp , endStamp , & secs , & microsecs );
119
- elog (INFO , "analyze \"%s\" took %.02f seconds" , get_rel_name (relOid ), ((double )secs ) + ((double )microsecs )/1.0e6 );
388
+ elog (INFO , "analyze \"%s\" took %.02f seconds" ,
389
+ get_rel_name (relOid ), ((double )secs ) + ((double )microsecs )/1.0e6 );
120
390
}
121
391
122
392
@@ -291,11 +561,76 @@ _PG_init(void)
291
561
NULL
292
562
);
293
563
564
+ DefineCustomEnumVariable (
565
+ "online_analyze.table_type" ,
566
+ "Type(s) of table for onlyne analyze: all(default), persistent, temporary, none" ,
567
+ NULL ,
568
+ & online_analyze_table_type ,
569
+ #if PG_VERSION_NUM >= 80400
570
+ online_analyze_table_type ,
571
+ #endif
572
+ online_analyze_table_type_options ,
573
+ PGC_USERSET ,
574
+ #if PG_VERSION_NUM >= 80400
575
+ GUC_NOT_IN_SAMPLE ,
576
+ #if PG_VERSION_NUM >= 90100
577
+ NULL ,
578
+ #endif
579
+ #endif
580
+ NULL ,
581
+ NULL
582
+ );
583
+
584
+ DefineCustomStringVariable (
585
+ "online_analyze.exclude_tables" ,
586
+ "List of tables which will not online analyze" ,
587
+ NULL ,
588
+ & excludeTables .tableStr ,
589
+ #if PG_VERSION_NUM >= 80400
590
+ "" ,
591
+ #endif
592
+ PGC_USERSET ,
593
+ 0 ,
594
+ #if PG_VERSION_NUM >= 90100
595
+ excludeTablesCheck ,
596
+ excludeTablesAssign ,
597
+ #else
598
+ excludeTablesAssign ,
599
+ #endif
600
+ excludeTablesShow
601
+ );
602
+
603
+ DefineCustomStringVariable (
604
+ "online_analyze.include_tables" ,
605
+ "List of tables which will online analyze" ,
606
+ NULL ,
607
+ & includeTables .tableStr ,
608
+ #if PG_VERSION_NUM >= 80400
609
+ "" ,
610
+ #endif
611
+ PGC_USERSET ,
612
+ 0 ,
613
+ #if PG_VERSION_NUM >= 90100
614
+ includeTablesCheck ,
615
+ includeTablesAssign ,
616
+ #else
617
+ includeTablesAssign ,
618
+ #endif
619
+ includeTablesShow
620
+ );
294
621
}
295
622
296
623
void _PG_fini (void );
297
624
void
298
625
_PG_fini (void )
299
626
{
300
627
ExecutorEnd_hook = oldhook ;
628
+
629
+ if (excludeTables .tables )
630
+ free (excludeTables .tables );
631
+ if (includeTables .tables )
632
+ free (includeTables .tables );
633
+
634
+ excludeTables .tables = includeTables .tables = NULL ;
635
+ excludeTables .nTables = includeTables .nTables = 0 ;
301
636
}
0 commit comments