Optimize PortMAC query

* We meant well but it turns out that the array unnest and join is
  actually very slow, as the join arguments do not get pushed down
  into the CTE (in Postgres 9/10 at least, later versions remove some
  of the optimization barriers in that specifc type of query)
* This caused a seq scan on both device and device_port, and the query
  is executed many times during macsuck
* The query is now rewritten to use ANY (macaddr[]) and without CTE,
  which seems to be around 20x faster
This commit is contained in:
Christian Ramseyer
2020-01-31 10:32:02 +01:00
parent b032ebc18e
commit 031c3e6d95
2 changed files with 3 additions and 11 deletions

View File

@@ -11,17 +11,9 @@ __PACKAGE__->table_class('DBIx::Class::ResultSource::View');
__PACKAGE__->table("port_macs"); __PACKAGE__->table("port_macs");
__PACKAGE__->result_source_instance->is_virtual(1); __PACKAGE__->result_source_instance->is_virtual(1);
__PACKAGE__->result_source_instance->view_definition(<<ENDSQL __PACKAGE__->result_source_instance->view_definition(<<ENDSQL
SELECT dp.ip, dp.mac SELECT ip, mac FROM device where mac = any (?::macaddr[])
FROM
(SELECT ip, mac FROM device
UNION UNION
SELECT ip, mac FROM device_port) dp SELECT ip, mac FROM device_port dp where mac = any (?::macaddr[])
INNER JOIN
(SELECT unnest( ? ::macaddr[] )) locals(m)
ON (dp.mac = locals.m ::macaddr)
ENDSQL ENDSQL
); );

View File

@@ -37,7 +37,7 @@ sub get_port_macs {
my $macs my $macs
= schema('netdisco')->resultset('Virtual::PortMacs')->search({}, = schema('netdisco')->resultset('Virtual::PortMacs')->search({},
{ bind => [$bindarray], select => [ 'mac', 'ip' ], group_by => [ 'mac', 'ip' ] } ); { bind => [$bindarray, $bindarray], select => [ 'mac', 'ip' ], group_by => [ 'mac', 'ip' ] } );
my $cursor = $macs->cursor; my $cursor = $macs->cursor;
while ( my @vals = $cursor->next ) { while ( my @vals = $cursor->next ) {
$port_macs->{ $vals[0] } = $vals[1]; $port_macs->{ $vals[0] } = $vals[1];