1
+ -- Copyright 2025 shaneborden
2
+ --
3
+ -- Licensed under the Apache License, Version 2.0 (the "License");
4
+ -- you may not use this file except in compliance with the License.
5
+ -- You may obtain a copy of the License at
6
+ --
7
+ -- https://www.apache.org/licenses/LICENSE-2.0
8
+ --
9
+ -- Unless required by applicable law or agreed to in writing, software
10
+ -- distributed under the License is distributed on an "AS IS" BASIS,
11
+ -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ -- See the License for the specific language governing permissions and
13
+ -- limitations under the License.
14
+
15
+ /* Helpful Links
16
+ https://cloud.google.com/alloydb/docs/columnar-engine/manage-content-recommendations
17
+ https://medium.com/google-cloud/alloydbs-columnar-store-how-to-preserve-it-during-failovers-and-restarts-141a8466772 */
18
+
19
+ /* determine columnar engine settings */
20
+ select name,setting,boot_val,reset_val from pg_settings where name like ' %google_columnar_engine%' order by 1 ;
21
+
22
+ /* Set a population policy */
23
+ SELECT google_columnar_engine_add_policy(' RECOMMEND_AND_POPULATE_COLUMNS' ,' IMMEDIATE' ,0 ,' HOURS' );
24
+ -- IMMEDIATE - runs immediately one time. When you use this value, specify 0 and 'HOURS' for the duration and time_unit parameters.
25
+ -- AFTER - runs once when the duration time_unit amount of time passes
26
+ -- EVERY - runs repeatedly every duration time_unit amount of time
27
+
28
+ /* Execute a recommendation */
29
+ SELECT google_columnar_engine_run_recommendation(102400 ,' PERFORMANCE_OPTIMAL' );
30
+
31
+ /* check from psql if columnar is enabled */
32
+ postgres= # show google_columnar_engine.enabled;
33
+ google_columnar_engine .enabled
34
+ -- ------------------------------
35
+ off
36
+
37
+ /* To show columnar messages in cloud logging */
38
+ textPayload= ~" population_jobs.cc|Invalidating columnar|population.cc|columnar"
39
+
40
+ /* To Force a SEQ Scan for invalid blocks; this is the default now; Use this for debugging only */
41
+ set session google_columnar_engine .rowstore_scan_mode to 1 ;
42
+
43
+ /* To show the refresh threshold (based on invalid blocks vs total blocks) */
44
+ show google_columnar_engine .refresh_threshold_percentage ;
45
+
46
+ /* To show the number of DML operations on base table required before the refresh_threshold_percentage kicks in */
47
+ show google_columnar_engine .refresh_threshold_scan_count ;
48
+
49
+ /* to force a columnar scan; generally isnt needed, this is for testing / debugging only */
50
+ set session google_columnar_engine .force_columnar_mode to true;
51
+
52
+ /* other GUC to influence CE costing, this is for testing / debugging only */
53
+ set session enable_cache_aware_costing = true
54
+ set session google_columnar_engine .bump_columnar_scan_cost = false
55
+
56
+ /* to force columnar using pg_hint_plan */
57
+ /* + ColumnarScan(xxx) */
58
+
59
+ /* To manually run the job: */
60
+ SELECT google_columnar_engine_recommend();
61
+
62
+ /* To view the list of recommended columns: */
63
+ SELECT * FROM g_columnar_recommended_columns;
64
+ SELECT database_name, schema_name, relation_name, column_name FROM g_columnar_recommended_columns;
65
+
66
+ /* To add a table */
67
+ SELECT google_columnar_engine_add(' t1' );
68
+ select google_columnar_engine_add(relation => ' public.t1' , in_background => TRUE);
69
+
70
+ /* To add a table with a subset of columns */
71
+ SELECT google_columnar_engine_add(' public.t1' , ' a,b,c,f,' );
72
+
73
+ /* To remove a table */
74
+ SELECT google_columnar_engine_drop(' t1' );
75
+ SELECT google_columnar_engine_drop(' public.t1' );
76
+
77
+ /* To disable columnar for a query in a session */
78
+ set session google_columnar_engine .enable_columnar_scan TO ' off' ;
79
+
80
+ /* to Refresh a table */
81
+ select google_columnar_engine_refresh(' public.t1' );
82
+
83
+ select google_columnar_engine_refresh(relation => ' public.t1' , in_background => TRUE);
84
+
85
+ /* to check columar jobs */
86
+ select * from g_columnar_jobs;
87
+
88
+ /* To view the list of recommended column detail: */
89
+ SELECT
90
+ crc .database_name as database_name,
91
+ crc .schema_name AS schema_name,
92
+ crc .relation_name AS table_name,
93
+ pi .inhparent ::regclass,
94
+ crc .column_name ,
95
+ crc .column_format ,
96
+ crc .compression_level ,
97
+ crc .estimated_size_in_bytes
98
+ FROM public .g_columnar_recommended_columns_internal /* g_columnar_recommended_columns */ crc
99
+ JOIN pg_stat_all_tables ps
100
+ ON ps .schemaname ::text = crc .schema_name
101
+ AND ps .relname ::text = crc .relation_name
102
+ JOIN pg_class pc
103
+ ON ps .relid = pc .oid
104
+ LEFT JOIN pg_catalog .pg_inherits pi
105
+ ON ps .relid = pi .inhrelid
106
+ ORDER BY 1 ,2 ,4 NULLS LAST;
107
+
108
+ /* to display table name without column detail */
109
+ SELECT
110
+ crc .database_name as database_name,
111
+ crc .schema_name AS schema_name,
112
+ crc .relation_name AS table_name,
113
+ pi .inhparent ::regclass,
114
+ crc .column_format ,
115
+ crc .compression_level ,
116
+ SUM (crc .estimated_size_in_bytes ) as total_bytes,
117
+ pg_size_pretty(SUM (crc .estimated_size_in_bytes )) as pretty_total_size
118
+ FROM g_columnar_recommended_columns crc
119
+ JOIN pg_stat_all_tables ps
120
+ ON ps .schemaname ::text = crc .schema_name
121
+ AND ps .relname ::text = crc .relation_name
122
+ JOIN pg_class pc
123
+ ON ps .relid = pc .oid
124
+ LEFT JOIN pg_catalog .pg_inherits pi
125
+ ON ps .relid = pi .inhrelid
126
+ GROUP BY crc .database_name , crc .schema_name , crc .relation_name , pi .inhparent ::regclass,crc .column_format ,crc .compression_level
127
+ ORDER BY 1 ,2 ,4 NULLS LAST;
128
+
129
+
130
+ /* List of items in the column store */
131
+ SELECT
132
+ database_name,
133
+ schema_name,
134
+ relation_name,
135
+ column_name,
136
+ column_type,
137
+ status,
138
+ size_in_bytes,
139
+ last_accessed_time,
140
+ num_times_accessed
141
+ FROM
142
+ g_columnar_columns;
143
+
144
+ SELECT
145
+ *
146
+ FROM
147
+ g_columnar_columns;
148
+
149
+ SELECT
150
+ *
151
+ FROM
152
+ g_columnar_relations
153
+ ORDER BY
154
+ relation_name;
155
+
156
+
157
+ /* To see current status of items in columnstore */
158
+ SELECT
159
+ schema_name,
160
+ relation_name,
161
+ status,
162
+ swap_status,
163
+ sum (end_block - start_block) ttl_block,
164
+ sum (invalid_block_count) invalid_block,
165
+ CASE WHEN sum (end_block - start_block) > 0 THEN
166
+ round(100 * sum (invalid_block_count) / sum (end_block - start_block), 1 )
167
+ ELSE 0 .0
168
+ END AS invalid_block_perc,
169
+ pg_size_pretty(sum (size)) ttl_size,
170
+ pg_size_pretty(sum (cached_size_bytes)) ttl_cached_size
171
+ FROM
172
+ g_columnar_units
173
+ WHERE
174
+ g_columnar_units .database_name = current_database()
175
+ and g_columnar_units .relation_name like ' %'
176
+ GROUP BY
177
+ schema_name,
178
+ relation_name,
179
+ status,
180
+ swap_status
181
+ ORDER BY
182
+ relation_name;
183
+
184
+ /* Check utilization of columnar memory */
185
+ SELECT
186
+ memory_name,
187
+ memory_total / 1024 / 1024 memory_total_MB,
188
+ memory_available / 1024 / 1024 memory_available_MB,
189
+ memory_available_percentage,
190
+ pg_size_pretty(google_columnar_engine_storage_cache_used()* 1024 * 1024 ) AS cc_storage_cache_used_mb,
191
+ pg_size_pretty(google_columnar_engine_storage_cache_available()* 1024 * 1024 ) AS cc_storage_cache_avail_mb,
192
+ pg_size_pretty((google_columnar_engine_storage_cache_available() - google_columnar_engine_storage_cache_used())* 1024 * 1024 ) as cc_storage_cache_free_mb
193
+ FROM
194
+ g_columnar_memory_usage;
195
+
196
+ /* Check non default "google" postgres params */
197
+ SELECT
198
+ s .name AS " Parameter" ,
199
+ pg_catalog .current_setting (s .name ) AS " Value"
200
+ FROM
201
+ pg_catalog .pg_settings s
202
+ WHERE
203
+ 1 = 1
204
+ -- AND s.source <> 'default'
205
+ -- AND s.setting IS DISTINCT FROM s.boot_val
206
+ AND lower (s .name ) LIKE ' %google%'
207
+ ORDER BY
208
+ 1 ;
209
+
210
+ /* To see Columnar engine column Swap-out */
211
+ SELECT
212
+ memory_name,
213
+ pg_size_pretty(memory_total) AS cc_allocated,
214
+ pg_size_pretty(memory_total - memory_available) AS cc_consumed,
215
+ pg_size_pretty(memory_available) cc_available,
216
+ -- google_columnar_engine_storage_cache_total() as cc_storage_cache_avail_mb, /* Future function */
217
+ google_columnar_engine_storage_cache_used() AS cc_storage_cache_used_mb,
218
+ google_columnar_engine_storage_cache_available() AS cc_storage_cache_avail_mb,
219
+ CASE WHEN google_columnar_engine_storage_cache_used() > 0 THEN
220
+ ' Swapped-out Column(s)'
221
+ ELSE
222
+ NULL
223
+ END AS " SwapOut" ,
224
+ (
225
+ SELECT
226
+ CONCAT_WS(' -' , STRING_AGG(DISTINCT g_columnar_units .relation_name , ' /' ), STATUS, swap_status)
227
+ FROM
228
+ g_columnar_units
229
+ GROUP BY
230
+ status,
231
+ swap_status) AS current_obj
232
+ FROM
233
+ g_columnar_memory_usage
234
+ WHERE
235
+ memory_name = ' main_pool' ;
236
+
237
+
238
+ /* To populate many tables manually */
239
+ do
240
+ $$
241
+ declare
242
+ f record;
243
+ gResult numeric ;
244
+ begin_timestamp timestamp ;
245
+ age_text text ;
246
+ begin
247
+ for f in SELECT
248
+ n .nspname as schemaname,
249
+ c .oid ::regclass::text AS table_name,
250
+ c .oid as oid ,
251
+ pi .inhparent ::regclass::text AS top_table_name,
252
+ pg_total_relation_size(c .oid ) as size,
253
+ pg_size_pretty(pg_total_relation_size(c .oid )) as pretty_size
254
+ FROM pg_class c
255
+ JOIN pg_namespace n on c .relnamespace = n .oid
256
+ LEFT JOIN pg_inherits pi on c .oid = pi .inhrelid
257
+ WHERE c .relkind IN (' r' , ' t' , ' m' )
258
+ AND (n .nspname NOT IN (' pg_toast' ) AND n .nspname LIKE ' %' )
259
+ -- AND (c.oid::regclass::text LIKE '%' AND pi.inhparent::regclass::text LIKE '%')
260
+ AND (c .oid ::regclass::text LIKE ' table_name%' AND pi .inhparent ::regclass::text LIKE ' table_partiton_name%' )
261
+ ORDER BY 2 NULLS LAST
262
+ loop
263
+ BEGIN
264
+ SELECT clock_timestamp() into begin_timestamp;
265
+ -- SELECT google_columnar_engine_add(f.oid,'[comma separated column list]') into gResult; /* us this if there are specific cols */
266
+ SELECT google_columnar_engine_add(f .oid ) into gResult;
267
+ SELECT age(clock_timestamp(),begin_timestamp)::text into age_text;
268
+ raise notice ' % % % % % %' , f .top_table_name , f .table_name , ' google_columnar_engine_add result: ' , gResult, ' time: ' , age_text;
269
+ EXCEPTION WHEN OTHERS THEN
270
+ raise notice ' % % % %' , f .top_table_name , f .table_name , ' exception result' , gResult;
271
+ END;
272
+ end loop;
273
+ end;
274
+ $$;
275
+
276
+
277
+ /* To refresh many tables manually */
278
+ do
279
+ $$
280
+ declare
281
+ f record;
282
+ gResult numeric ;
283
+ begin
284
+ for f in SELECT
285
+ n .nspname as schemaname,
286
+ c .oid ::regclass::text AS table_name,
287
+ c .oid as oid ,
288
+ pi .inhparent ::regclass::text AS top_table_name,
289
+ pg_total_relation_size(c .oid ) as size,
290
+ pg_size_pretty(pg_total_relation_size(c .oid )) as pretty_size
291
+ FROM pg_class c
292
+ JOIN pg_namespace n on c .relnamespace = n .oid
293
+ LEFT JOIN pg_inherits pi on c .oid = pi .inhrelid
294
+ WHERE c .relkind IN (' r' , ' t' , ' m' )
295
+ AND (n .nspname NOT IN (' pg_toast' ) AND n .nspname LIKE ' %' )
296
+ -- AND (c.oid::regclass::text LIKE '%' AND pi.inhparent::regclass::text LIKE '%')
297
+ AND (c .oid ::regclass::text LIKE ' table_name%' AND pi .inhparent ::regclass::text LIKE ' table_partiton_name%' )
298
+ ORDER BY 2 NULLS LAST
299
+ loop
300
+ BEGIN
301
+ SELECT google_columnar_engine_refresh(f .oid ) into gResult;
302
+ raise notice ' % % % %' , f .top_table_name , f .table_name , ' google_columnar_engine_refresh result: ' , gResult;
303
+ EXCEPTION WHEN OTHERS THEN
304
+ raise notice ' % % % %' , f .top_table_name , f .table_name , ' exception result' , gResult;
305
+ END;
306
+ end loop;
307
+ end;
308
+ $$;
309
+
310
+ /* To drop many tables manually */
311
+ do
312
+ $$
313
+ declare
314
+ f record;
315
+ gResult numeric ;
316
+ begin
317
+ for f in SELECT
318
+ n .nspname as schemaname,
319
+ c .oid ::regclass::text AS table_name,
320
+ c .oid as oid ,
321
+ pi .inhparent ::regclass::text AS top_table_name,
322
+ pg_total_relation_size(c .oid ) as size,
323
+ pg_size_pretty(pg_total_relation_size(c .oid )) as pretty_size
324
+ FROM pg_class c
325
+ JOIN pg_namespace n on c .relnamespace = n .oid
326
+ LEFT JOIN pg_inherits pi on c .oid = pi .inhrelid
327
+ JOIN g_columnar_units ce on (ce .schema_name = n .nspname and ce .relation_name = c .oid ::regclass::text )
328
+ WHERE c .relkind IN (' r' , ' t' , ' m' )
329
+ AND (n .nspname NOT IN (' pg_toast' ) AND n .nspname LIKE ' %' )
330
+ -- AND (c.oid::regclass::text LIKE '%' AND pi.inhparent::regclass::text LIKE '%')
331
+ AND (c .oid ::regclass::text LIKE ' table_name%' AND pi .inhparent ::regclass::text LIKE ' table_partiton_name%' )
332
+ ORDER BY 2 NULLS LAST
333
+ loop
334
+ BEGIN
335
+ SELECT google_columnar_engine_drop(f .oid ) into gResult;
336
+ raise notice ' % % % %' , f .top_table_name , f .table_name , ' google_columnar_engine_add result: ' , gResult;
337
+ EXCEPTION WHEN OTHERS THEN
338
+ raise notice ' % % % %' , f .top_table_name , f .table_name , ' exception result' , gResult;
339
+ END;
340
+ end loop;
341
+ end;
342
+ $$;
0 commit comments