Scheme Service
The Scheme service manages the YDB path hierarchy — databases, directories, tables,
topics, and other named objects. It is available through driver.scheme_client on
both the synchronous and asynchronous driver.
A typical use case is ensuring that a directory tree exists before creating tables, or introspecting the schema at runtime.
Directories
Create a Directory
Directories work like filesystem folders. They are used to organise tables and other objects within a database:
driver.scheme_client.make_directory("/local/my_app")
# Nested directories must be created one level at a time
driver.scheme_client.make_directory("/local/my_app/production")
driver.scheme_client.make_directory("/local/my_app/staging")
A helper to ensure an entire path exists, creating each missing segment:
import os
import ydb
def ensure_path(driver: ydb.Driver, path: str) -> None:
parts = []
head = path.rstrip("/")
while head:
try:
if driver.scheme_client.describe_path(head).is_directory_or_database():
break
except ydb.SchemeError:
pass
parts.append(head)
head = os.path.dirname(head).rstrip("/")
for p in reversed(parts):
driver.scheme_client.make_directory(p)
Remove a Directory
The directory must be empty before it can be removed:
driver.scheme_client.remove_directory("/local/my_app/staging")
List a Directory
list_directory returns a SchemeEntry for each immediate child of the path,
plus a self entry describing the path itself:
listing = driver.scheme_client.list_directory("/local/my_app")
# listing.self — SchemeEntry for /local/my_app itself
print(listing.self.name, listing.self.type)
# listing.children — list of SchemeEntry for immediate children
for entry in listing.children:
print(entry.name, entry.type)
Filter by type to find, for example, all tables in a directory:
listing = driver.scheme_client.list_directory("/local/my_app")
tables = [e for e in listing.children if e.is_table()]
topics = [e for e in listing.children if e.type == ydb.SchemeEntryType.TOPIC]
Describing Paths
describe_path returns a SchemeEntry for any path — table, topic, directory,
coordination node, etc.:
entry = driver.scheme_client.describe_path("/local/my_app/users")
print(entry.name) # "users"
print(entry.owner) # owner login
print(entry.type) # SchemeEntryType.TABLE
print(entry.size_bytes) # approximate size
SchemeEntry
Every scheme object is described by a SchemeEntry:
Field |
Description |
|---|---|
|
Object name (last path component). |
|
|
|
Login of the object owner. |
|
Approximate on-disk size (tables only; 0 for directories). |
|
Explicit ACL entries set on this object. |
|
Effective ACL entries (including inherited from parent). |
Convenience predicates:
entry.is_directory() # DIRECTORY
entry.is_database() # DATABASE
entry.is_table() # TABLE (row-oriented)
entry.is_column_table() # COLUMN_TABLE (column-oriented)
entry.is_column_store() # COLUMN_STORE
entry.is_any_table() # TABLE or COLUMN_TABLE
entry.is_directory_or_database()
entry.is_coordination_node() # COORDINATION_NODE
entry.is_external_table() # EXTERNAL_TABLE
entry.is_external_data_source() # EXTERNAL_DATA_SOURCE
entry.is_view() # VIEW
entry.is_resource_pool() # RESOURCE_POOL
entry.is_sysview() # SYS_VIEW
SchemeEntryType enum values:
Value |
Meaning |
|---|---|
|
Directory |
|
Database root |
|
Row-oriented table |
|
Column-oriented table |
|
Column store (groups column tables) |
|
Topic (message queue) |
|
Legacy PersQueue group (predecessor of Topic) |
|
Coordination service node |
|
External table (federated query) |
|
External data source (federated query) |
|
View |
|
Sequence (auto-increment counter) |
|
Async replication object |
|
Data transfer object |
|
Resource pool (workload management) |
|
System view |
|
Unknown or unsupported type |
Async Usage
The async scheme client has the same methods with await:
import asyncio
import ydb
async def main():
async with ydb.aio.Driver(
endpoint="grpc://localhost:2136", database="/local"
) as driver:
await driver.wait(timeout=5, fail_fast=True)
await driver.scheme_client.make_directory("/local/my_app")
listing = await driver.scheme_client.list_directory("/local")
for entry in listing.children:
print(entry.name, entry.type)
entry = await driver.scheme_client.describe_path("/local/my_app")
print(entry.is_directory())
await driver.scheme_client.remove_directory("/local/my_app")
asyncio.run(main())
Common Pattern: Idempotent Directory Setup
When initialising an application it is common to create the directory structure once and tolerate the case where it already exists:
import ydb
def setup_schema(driver: ydb.Driver, base_path: str) -> None:
for subdir in ("tables", "topics", "coordination"):
path = f"{base_path}/{subdir}"
try:
driver.scheme_client.make_directory(path)
except ydb.SchemeError:
pass # already exists
with ydb.QuerySessionPool(driver) as pool:
pool.execute_with_retries(
f"CREATE TABLE IF NOT EXISTS `{base_path}/tables/events` "
"(id Uint64, payload Utf8, PRIMARY KEY (id))"
)