Lookup performance of Numeric vs String I'm working on a project that is using the instagram key format.

TL;DR 64-bit integer ids.

They'll be used for lookups, and we also like them for sorting and batching since they will naturally sort by creation time.

The values are between 2^63 and 2^64, so (just) too big to fit inside a BIGINT.

So it seems our options for storage are numeric(20) or varchar. varchar is not as ideal since we'd have to zero pad them for sorting to work, but would there be a performance hit to using a numeric for lookups?
numeric is bigger and slower than bigint (8 bytes) in every respect. Unfortunately, like you said, bigint is just not big enough. Maximum is 2^63-1 = 9223372036854775801, 19 decimal digits.
varchar or text (same thing internally) are bigger and slower, yet. Plus, character types are encumbered with COLLATION rules unless explicitly defined without.
SELECT pg_column_size(numeric '18446744073709551616')  -- 16 bytes in RAM
     , pg_column_size(text    '18446744073709551616')  -- 24 bytes in RAM

(But 13 / 21 bytes on disk.) See:
db&lt;&gt;fiddle here
numeric saves additional space for trailing zeroes, which text cannot.
numeric disallows non-numbers from being stored and enforces some sanity out of the box.
Faced with your requirements, choose numeric and never look back.
Related:

What is the overhead for varchar(n)?


Or you could install the extension pguint by Peter Eisentraut, one of the core hackers of the Postgres project.
Be sure to read the readme first. The extension provides several additional (most of them unsigned) integer types. You might just extract uint8 (unsigned 64-bit integer) and ditch the rest to avoid over-crowding the type system.