QuestDB is written in Java and can be used as any other Java library. Moreover, it is a single JAR with no additional dependencies.
To include QuestDB in your project, use the latest Maven coordinates:
TableWriter facilitates table writes. To successfully create an instance
TableWriter, the table must:
- already exist
- have no other open writers against it as the
TableWriterconstructor will attempt to obtain an exclusive cross-process lock on the table.
1 - Create an instance of TableWriter
In this case, we use engine but we can also use TableWriter constructor directly.
writer instance must be eventually released to release resources. In this
case, it will be released back to the engine for re-use. Constructing a new
writer is a resource-intensive operation and it will allocate memory on JVM
heap. Writers lifecycle should be carefully considered for your particular use
2 - Create a new row
Although this operation semantically looks like a new object creation, the row instance is actually being re-used under the hood. A Timestamp is necessary to determine a partition for the new row. Its value has to be either increment or stay the same as the last row. When the table is not partitioned and does not have a designated timestamp column, timestamp value can be 0, e.g.
3 - Populate columns There are put* methods for every supported data type.
Columns are updated by an index for performance reasons:
Column update order is not important and update can be sparse. All unset columns will default to NULL values.
4 - Append row It is a trivial and lightweight method call:
Appended rows are not visible to readers until they are committed. An unneeded row can also be canceled if required.
A pending row is automatically cancelled when
writer.newRow() is called.
5 - Commit changes
writer.commit commits changes, which makes them visible
to readers. This method call is atomic and has a complexity of O(1).
Java users can use the
SqlCompiler to run SQL queries like they would do in
the Web Console for example.
configurationholds various settings that can be overridden via a subclass. Most importantly configuration is bound to the database root - directory where table sub-directories will be created.
engineis a concurrent pool of table readers and writers.
compileris the entry point for QuestDB's SQL engine.
The following will create a new table with the specifications set below.
Fetching query results
Querying data is a three-step process:
- 1 - Compile the SQL text to an instance of
RecordCursorFactory, an instance that encapsulates execution plan. You can run custom SQL queries by instantiating
- 2 - Create a
RecordCursorinstance using a factory from step 1.
- 3 - Iterate on
RecordCursorto read the data.
Component life cycle
1 - Engine
This is a thread-safe, concurrent and non-blocking pool of TableReader and TableWriter instances. Ideally, there should be only one per database location.
2 - SqlCompiler
This is a totally single-threaded, factory-style instance
3 - RecordCursorFactory
Execution plan of respective SQL, also single-threaded. The instance is reusable as far as the creation of RecordCursor is concerned and should be retained until data access is no longer needed. It can be closed explicitly via close() method.
4 - RecordCursor
This is a data iterator. The cursor has a fixed record instance, which is a
moving window on the data set.
next() calls push this "window" down one record
at a time.
InfluxDB sender library
QuestDB library provides fast and efficient way of sending line protocol
messages. Sender implementation entry point is
io.questdb.cutlass.line.udp.LineProtoSender, it is fully zero-GC and has
latency in a region of 200ns per message.
- Step 1: Create an instance of
|Network interface to use to send messages.|
|Destination IP address|
|Send buffer capacity to batch messages. Do not configure this buffer over the MTU size|
|UDP packet TTL. Set this number appropriate to how many VLANs your messages have to traverse before reaching the destination|
- Step 2: Create
entriesby building each entry's tagset and fieldset.
|Element||Description||Can be repeated|
|Specify which table the data is to be written into||no|
|Use to add a new key-value entry as metadata||yes|
|Use to add a new key-value entry as reading||yes|
|Specify the timestamp for the reading||no|
You can chain several tags and fields, e.g
Sender will send message as soon as send buffer is full. To send messages before
buffer fills up you can use
This example sends multicast messages to
220.127.116.11:9009. In this mode multiple
QuestDB instances can receive the same message.