Data types

The type system is derived from Java types.

Type NameStorage bitsNullableDescription
boolean1NoBoolean true or false.
ipv432Yes0.0.0.1 to 255.255.255.255
byte8NoSigned integer, -128 to 127.
short16NoSigned integer, -32,768 to 32,767.
char16Yesunicode character.
int32YesSigned integer, -2,147,483,648 to 2,147,483,647.
float32YesSingle precision IEEE 754 floating point value.
symbol32YesA symbol, stored as a 32-bit signed index into the symbol table. Each index corresponds to a string value. The index is transparently translated to the string value. Symbol table is stored separately from the column data.
varchar128 + utf8LenYesLength-prefixed sequence of UTF-8 encoded characters, stored using a 128-bit header and UTF-8 encoded data. Sequences shorter than 9 bytes are fully inlined within the header and do not occupy any additional data space.
string96+n*16YesLength-prefixed sequence of UTF-16 encoded characters whose length is stored as signed 32-bit integer with maximum value of 0x7fffffff.
long64YesSigned integer, -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807.
date64YesSigned offset in milliseconds from Unix Epoch.
timestamp64YesSigned offset in microseconds from Unix Epoch.
double64YesDouble precision IEEE 754 floating point value.
uuid128YesUUID values. See also the UUID type.
binary64+n*8YesLength-prefixed sequence of bytes whose length is stored as signed 64-bit integer with maximum value of 0x7fffffffffffffffL.
long256256YesUnsigned 256-bit integer. Does not support arithmetic operations, only equality checks. Suitable for storing a hash code, such as crypto public addresses.
geohash(<size>)8-64YesGeohash with precision specified as a number followed by b for bits, c for chars. See the geohashes documentation for details on use and storage.
arraySee descriptionYesHeader: 20 + 4 * nDims bytes. Payload: dense array of values. Example: DOUBLE[3][4]: header 28 bytes, payload 3*4*8 = 96 bytes.
interval128YesPair of timestamps representing a time interval. Not a persisted type: you can use it in expressions, but can't have a database column of this type.

VARCHAR and STRING considerations

QuestDB supports two types for storing strings: VARCHAR and STRING.

Most users should use VARCHAR. It uses the UTF-8 encoding, whereas STRING uses UTF-16, which is less space-efficient for strings containing mostly ASCII characters. QuestDB keeps supporting it only to maintain backward compatibility.

Additionally, VARCHAR includes several optimizations for fast access and storage.

TIMESTAMP and DATE considerations

While the date type is available, we highly recommend using the timestamp instead. The only material advantage of date is a wider time range, but timestamp is adequate in virtually all cases. It has microsecond resolution (vs. milliseconds for date), and is fully supported by all date/time functions, while support for date is limited.

Limitations for variable-sized types

The maximum size of a single VARCHAR field is 268 MB, and the maximum total size of a VARCHAR column in a single partition is 218 TB.

The maximum size of a BINARY field is defined by the limits of the 64-bit signed integer (8,388,608 petabytes).

The maximum size of a STRING field is defined by the limits of the 32-bit signed integer (1,073,741,824 characters).

The maximum number of dimensions an array can have is 32. The hard limit on the total number of elements in an array (lengths of all dimensions multiplied together) is 2^31 - 1 divided by the byte size of array element. For a DOUBLE[], this is 2^28 - 1 or 268,435,455. The actual limit QuestDB will enforce is configurable via cairo.max.array.element.count, with the default of 10,000,000. The length of each individual dimension has a limit of 2^28 - 1 or 268,435,455, regardless of element size.

Type nullability

Many nullable types reserve a value that marks them NULL:

Type NameNull valueDescription
floatNaNAs defined by IEEE 754 (java.lang.Float.NaN).
doubleNaNAs defined by IEEE 754 (java.lang.Double.NaN).
long2560x8000000000000000800000000000000080000000000000008000000000000000The value equals four consecutive long null literals.
long0x8000000000000000LMinimum possible value a long can take, -2^63.
date0x8000000000000000LMinimum possible value a long can take, -2^63.
timestamp0x8000000000000000LMinimum possible value a long can take, -2^63.
int0x80000000Minimum possible value an int can take, -2^31.
uuid80000000-0000-0000-8000-000000000000Both 64 highest bits and 64 lowest bits set to -2^63.
char0x0000The zero char (NUL in ASCII).
geohash(byte)0xffValid for geohashes of 1 to 7 bits (inclusive).
geohash(short)0xffffValid for geohashes of 8 to 15 bits (inclusive).
geohash(int)0xffffffffValid for geohashes of 16 to 31 bits (inclusive).
geohash(long)0xffffffffffffffffValid for geohashes of 32 to 60 bits (inclusive).
symbol0x80000000Symbol is stored as an int offset into a lookup file. The value -1 marks it NULL.
ipv40.0.0.0 (0x00000000)IPv4 address is stored as a 32-bit integer and the zero value represents NULL.
varcharN/AVarchar column has an explicit NULL marker in the header.
stringN/AString column is length-prefixed, the length is an int and -1 marks it NULL.
binaryN/ABinary column is length prefixed, the length is a long and -1 marks it NULL.
arrayN/AArray column marks a NULL value with a zero in the size field of the header.

To filter columns that contain, or don't contain, NULL values use a filter like:

SELECT * FROM <table> WHERE <column> = NULL;
SELECT * FROM <table> WHERE <column> != NULL;

Alternatively, from version 6.3 use the NULL equality operator aliases:

SELECT * FROM <table> WHERE <column> IS NULL;
SELECT * FROM <table> WHERE <column> IS NOT NULL;
note

NULL values still occupy disk space.

The UUID type

QuestDB natively supports the UUID type, which should be used for UUID columns instead of storing UUIDs as strings. UUID columns are internally stored as 128-bit integers, allowing more efficient performance particularly in filtering and sorting. Strings inserted into a UUID column is permitted but the data will be converted to the UUID type.

Inserting strings into a UUID column
CREATE TABLE my_table (
id UUID
);
[...]
INSERT INTO my_table VALUES ('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11');
[...]
SELECT * FROM my_table WHERE id = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11';

If you use the PostgreSQL Wire Protocol then you can use the uuid type in your queries. The JDBC API does not distinguish the UUID type, but the Postgres JDBC driver supports it in prepared statements:

UUID uuid = UUID.randomUUID();
PreparedStatement ps = connection.prepareStatement("INSERT INTO my_table VALUES (?)");
ps.setObject(1, uuid);

QuestDB Client Libraries can send UUIDs as strings to be converted to UUIDs by the server.

IPv4

QuestDB supports the IPv4 data type. It has validity checks and some IPv4-specific functions.

IPv4 addresses exist within the range of 0.0.0.1 - 255.255.255.255.

An all-zero address - 0.0.0.0 - is interpreted as NULL.

Create a column with the IPv4 data type like this:

-- Creating a table named traffic with two ipv4 columns: src and dst.
CREATE TABLE traffic (ts timestamp, src ipv4, dst ipv4) timestamp(ts) PARTITION BY DAY;

IPv4 addresses support a wide range of existing SQL functions, and there are some operators specifically for them. For a full list, see IPv4 Operators.

Limitations

You cannot auto-create an IPv4 column using the InfluxDB Line Protocol, since it doesn't support this type explicitly. The QuestDB server cannot distinguish between string and IPv4 data. However, you can insert IPv4 data into a pre-existing IPv4 column by sending IPs as strings.