Skip to content

Add functional index to ipam.ip_address model/table #11519

@tyler-8

Description

@tyler-8

NetBox version

v3.4.2

Feature type

Change to existing functionality

Proposed functionality

Create a functional index on the ipam.ip_address table. Which indexes the output of CAST(HOST(ipam.ipaddress)) so it isn't called on every execution of the query - which can be computationally expensive.

Use case

I've detailed my findings in this discussion thread.

Queries/searches for IPAddress filtered by parent Prefixes can be CPU intensive to the database and, depending on the parent prefix and IP addresses present, can be very inefficient when searching through hundreds of thousands of IPs (~260K) and only returning a few. Query time itself isn't terrible, but there is a noticeable uptick in CPU & DB worker threads/processes generated by this type of query compared to others - and that can be of concern to larger/high-volume instances.

The culprit is mostly with calling CAST(HOST("ipam_ipaddress"."address") AS INET)

return 'CAST(HOST(%s) AS INET) <<= %s' % (lhs, rhs), params
and the resulting sequential scans it must perform. Indexing address with btree or inet_ops makes little difference in performance and query cost.

But the above functional index is 1/3 the query cost (2264 vs 6632) and the query time is <=2ms (vs ~70ms). I observed a ~5MB increase (+8%) in table disk size (260K IPs) with this index, and new data insertion time seemed un-impacted in any noticeable way (Using the REST API: (0.0185s without index, 0.0166s with index)).

Additional metrics

Querying the /ipam/ip-addresses/ endpoint ~2K times with different prefixes as parent and 3 separate client processes:

  • No index: 6m18s
  • With index: 4m37s

Database changes

New index on address field.

CREATE INDEX ipam_ipaddress_address_host_idx ON ipam_ipaddress (cast(host(address) as inet));

One possible way is in a manually-defined migrations file:

operations = [
        migrations.RunSQL(
            sql="CREATE INDEX ipam_ipaddress_address_host_idx ON ipam_ipaddress (cast(host(address) as inet))",
            reverse_sql='DROP INDEX ipam_ipaddress_address_host_idx ON ipam_ipaddress'
        )
    ]

or it might be possible on the model itself via defining an index expression.

External dependencies

N/A

And thanks & credit to @candlerb & @kkthxbye-code for setting me down the path

Metadata

Metadata

Assignees

Labels

status: acceptedThis issue has been accepted for implementationtype: featureIntroduction of new functionality to the application

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions