#!/usr/bin/perl # Copyright (c) 2021-2023, PostgreSQL Global Development Group use strict; use warnings; # make sure we are in a sane environment. use DBI(); use DBD::Pg(); use Time::HiRes qw( usleep ualarm gettimeofday tv_interval ); use Getopt::Std; my %opt; getopts('d:b:s:veorauc', \%opt); if (!(scalar %opt && defined $opt{s})) { print <connect('DBI:Pg:dbname=' . $opt{d}); my %table; my @where; $table{message} = 1; if ($opt{a}) { if ($opt{r}) { push @where, "message.sections @ '{$opt{s}}'"; } else { foreach my $sid (split(/[,\s]+/, $opt{s})) { push @where, "message.mid = msp$sid.mid"; push @where, "msp$sid.sid = $sid"; $table{"message_section_map msp$sid"} = 1; } } } else { if ($opt{r}) { push @where, "message.sections && '{$opt{s}}'"; } else { $table{message_section_map} = 1; push @where, "message.mid = message_section_map.mid"; push @where, "message_section_map.sid in ($opt{s})"; } } my $outf; if ($opt{c}) { $outf = ($opt{u}) ? 'count( distinct message.mid )' : 'count( message.mid )'; } else { $outf = ($opt{u}) ? 'distinct( message.mid )' : 'message.mid'; } my $sql = "select $outf from " . join(', ', keys %table) . " where " . join(' AND ', @where) . ';'; if ($opt{v}) { print "$sql\n"; } if ($opt{e}) { my @plan = map { "$_->[0]\n" } @{ $dbi->selectall_arrayref("explain $sql") }; print @plan; } my $t0 = [gettimeofday]; my $count = 0; my $b = $opt{b}; $b ||= 1; my @a; foreach (1 .. $b) { @a = exec_sql($dbi, $sql); $count = $#a; } my $elapsed = tv_interval($t0, [gettimeofday]); if ($opt{o}) { foreach (@a) { print "$_->{mid}\t$_->{sections}\n"; } } print sprintf( "total: %.02f sec; number: %d; for one: %.03f sec; found %d docs\n", $elapsed, $b, $elapsed / $b, $count + 1); $dbi->disconnect; sub exec_sql { my ($dbi, $sql, @keys) = @_; my $sth = $dbi->prepare($sql) || die; $sth->execute(@keys) || die; my $r; my @row; while (defined($r = $sth->fetchrow_hashref)) { push @row, $r; } $sth->finish; return @row; }