@@ -262,3 +262,60 @@ SELECT 'count_matches', 'words_longtext', 'pg_builtin',
262262 (SELECT sum (regexp_count(longtext, ' \w +' )) FROM bench_data WHERE id <= 2500 ),
263263 (extract(epoch FROM clock_timestamp() - ts) * 1000 )::numeric (12 ,2 )
264264FROM (SELECT clock_timestamp() AS ts) t;
265+
266+ -- ============================================================
267+ -- 7. INDEX SCAN: re2 index support vs postgres index scan
268+ -- idx_btree re2match(col,'^lit') planner support -> text_pattern_ops range,
269+ -- vs postgres' own '~' prefix support on the same index
270+ -- idx_gin col @~ pat (gin_re2_ops, RE2 FilteredRE2 atoms)
271+ -- vs col ~ pat (pg_trgm gin_trgm_ops)
272+ -- enable_seqscan off so both engines are measured on their index, not a scan
273+ -- ============================================================
274+ SET enable_seqscan = off;
275+
276+ -- 7a. b-tree literal prefix (~11k rows in range, recheck cost visible)
277+ SELECT ' idx_btree' , ' prefix_literal' , ' re2' ,
278+ (SELECT count (* ) FROM bench_index_data WHERE re2match(email, ' ^user5' )),
279+ (extract(epoch FROM clock_timestamp() - ts) * 1000 )::numeric (12 ,2 )
280+ FROM (SELECT clock_timestamp() AS ts) t;
281+
282+ SELECT ' idx_btree' , ' prefix_literal' , ' pg_builtin' ,
283+ (SELECT count (* ) FROM bench_index_data WHERE email ~ ' ^user5' ),
284+ (extract(epoch FROM clock_timestamp() - ts) * 1000 )::numeric (12 ,2 )
285+ FROM (SELECT clock_timestamp() AS ts) t;
286+
287+ -- 7b. b-tree literal prefix + bounded char-class tail (prefix still extractable)
288+ SELECT ' idx_btree' , ' prefix_charclass' , ' re2' ,
289+ (SELECT count (* ) FROM bench_index_data WHERE re2match(email, ' ^user12[0-9]' )),
290+ (extract(epoch FROM clock_timestamp() - ts) * 1000 )::numeric (12 ,2 )
291+ FROM (SELECT clock_timestamp() AS ts) t;
292+
293+ SELECT ' idx_btree' , ' prefix_charclass' , ' pg_builtin' ,
294+ (SELECT count (* ) FROM bench_index_data WHERE email ~ ' ^user12[0-9]' ),
295+ (extract(epoch FROM clock_timestamp() - ts) * 1000 )::numeric (12 ,2 )
296+ FROM (SELECT clock_timestamp() AS ts) t;
297+
298+ -- 7c. GIN required literal atom (re2 keeps a tight candidate set; pg_trgm wins
299+ -- here because its per-candidate consistent check is far cheaper)
300+ SELECT ' idx_gin' , ' literal' , ' re2' ,
301+ (SELECT count (* ) FROM bench_index_data WHERE logline @~ ' error_code=123' ),
302+ (extract(epoch FROM clock_timestamp() - ts) * 1000 )::numeric (12 ,2 )
303+ FROM (SELECT clock_timestamp() AS ts) t;
304+
305+ SELECT ' idx_gin' , ' literal' , ' pg_builtin' ,
306+ (SELECT count (* ) FROM bench_index_data WHERE logline ~ ' error_code=123' ),
307+ (extract(epoch FROM clock_timestamp() - ts) * 1000 )::numeric (12 ,2 )
308+ FROM (SELECT clock_timestamp() AS ts) t;
309+
310+ -- 7d. GIN alternation (atoms on each branch)
311+ SELECT ' idx_gin' , ' alternation' , ' re2' ,
312+ (SELECT count (* ) FROM bench_index_data WHERE logline @~ ' error_code=(100|200|300)' ),
313+ (extract(epoch FROM clock_timestamp() - ts) * 1000 )::numeric (12 ,2 )
314+ FROM (SELECT clock_timestamp() AS ts) t;
315+
316+ SELECT ' idx_gin' , ' alternation' , ' pg_builtin' ,
317+ (SELECT count (* ) FROM bench_index_data WHERE logline ~ ' error_code=(100|200|300)' ),
318+ (extract(epoch FROM clock_timestamp() - ts) * 1000 )::numeric (12 ,2 )
319+ FROM (SELECT clock_timestamp() AS ts) t;
320+
321+ RESET enable_seqscan;
0 commit comments