Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

データベース (データの保存方法) #9

Open
Siroshun09 opened this issue Jan 29, 2023 · 4 comments
Open

データベース (データの保存方法) #9

Siroshun09 opened this issue Jan 29, 2023 · 4 comments

Comments

@Siroshun09
Copy link
Member

No description provided.

@Siroshun09
Copy link
Member Author

Siroshun09 commented Jan 29, 2023

CompoundTag にするメソッド (メモ)
BlockState -> NbtUtils#writeBlockState NbtUtils#readBlockState
BlockEntity -> BlockEntity#saveWithId BlockEntity#loadStatic

@LazyGon
Copy link
Member

LazyGon commented Jan 29, 2023

co_block_log
    epoch bigint NOT NULL, <- Instant.now().getEpochSeconds()
    nano int NOT NULL, <- Instant.now().getNano()
        PRIMARY KEY(epoch, nano)
    action tinyint NOT NULL, // <- source code defined
    cause int NOT NULL, // <- co_cause.id
    wid int NOT NULL, // <- co_world.id
    x int NOT NULL,
    y int NOT NULL,
    z int NOT NULL,
    block bigint index NOT NULL, // <- co_block.id
    rolled_back tinyint NOT NULL DEFAULT 0

co_cause
    id bigint NOT NULL autoincrement PRIMARY KEY,
    causeblock int, <- co_block.id
    causeentity int, <- co_entity.id

co_block
    id bigint NOT NULL autoincrement PRIMARY KEY,
    material int NOT NULL,
    state varchar(300),
    data mediumblob

co_material
    id int NOT NULL autoincrement PRIMARY KEY,
    namespace varchar(50) NOT NULL DEFAULT 'minecraft'
    key varchar(50) NOT NULL,
    UNIQUE(namespace, key)

co_entity_log
    epoch bigint NOT NULL, <- Instant.now().getEpochSeconds()
    nano int NOT NULL, <- Instant.now().getNano()
        PRIMARY KEY(epoch, nano)
    action tinyint NOT NULL, // kill, pickup(dropped item), throw(dropped item), place(armorstand, art, item frame)
    cause int NOT NULL, <- co_cause.id
    wid int NOT NULL, // <- co_world.id
    x int NOT NULL,
    y int NOT NULL,
    z int NOT NULL,
    entity int NOT NULL, <- co_entity.id
    rolled_back tinyint NOT NULL DEFAULT 0

co_entity
    id bigint NOT NULL PRIMARY KEY,
    type int NOT NULL, <- source code defined?
    nbt mediumblob NOT NULL, // if type == player nbt = uuid

co_world
    id int NOT NULL PRIMARY KEY,
    name varchar(50) NOT NULL unique 

co_coreprotect
    databaselock tinyint NOT NULL DEFAULT 0
    minecraftversion varchar(64) NOT NULL

@Siroshun09
Copy link
Member Author

Siroshun09 commented Jan 31, 2023

昨今の CP のデータベースサイズの激増を踏まえた意見

nano カラム

追加する理由は把握していないが、おそらくミリ秒単体での PK では重複する懸念や Instant の正確な保存を目的としたものと推測している。

しかし、Java のナノ秒は完全な正確性が担保されたものではなく、その更新頻度は必ずしもナノ秒単位ではないため、ときには同じ値を返すことがある (以下のコードで検証可能)。そのため、ミリ秒とナノ秒で複合 PK にしても重複の懸念が残っている。

for (int i = 0; i < 100; i++) {
    System.out.println(Instant.now().getNano()); // -> 同じ値が連続してプリントされる
}

私は現状の CP と同じ autoincrement id のままでいいと考える。

co_entity について

すべてのエンティティに対して完全な NBT を保存すると大変な容量になってしまうため、カスタム名やアイテムを持ってるなど、単にスポーンした状態と違うエンティティのみ NBT を保存するようにしたい。これの判定方法は要議論。

co_world

world の id を符号なしの tinyint (1 byte, 0 - 255) や smallint (2byte, 0 - 65535) で代用できないか検証したい。
具体的には、検索時のパフォーマンスに影響するか。
プログラミングでは byteshort より int の計算のほうが高速であるという事実 (StackOverflow「なぜ int は short や byte より高速に処理できる場合があるのか」)があるが、tinyintsmallint にすることでソレに類することが起きるかどうかが知りたい。
問題がないならば、21億もワールドを作ることは現実的ではないので、データサイズを半減できる smallint で代用したい。tinyint の最大値 255 はいつかは到達しそうな数字なので少し懸念が残る。

データサイズ1

テーブル名 1行あたりのデータサイズ (bytes) 現行のサイズ
co_block_log2 42 42 + mblob + blob
co_cause 16
co_block 12 + varchar(300) + mblob
co_material 4 + varchar(50) * 2 8 + varchar(255)
co_entity_log2 42 42 + mblob + blob
co_entity 12 + mblob 8 + blob
co_world 4 + varchar(50) 8 + varchar(255)

その他疑問点

  • co_world - ワールド名ではなくネームスペースで管理するべき?
  • co_container などのコンテナ操作はどのテーブルで行う?

Footnotes

  1. 整数型のストレージサイズについては 11.1.2 整数型 (真数値) - INTEGER、INT、SMALLINT、TINYINT、MEDIUMINT、BIGINT
    を元に算出。varcharmediumblob (mblob) はデータによって異なるため無視。

  2. nano を削除し autoincrement bigintid 導入や widsmallint 化を施した場合、44 bytes になる。 2

@LazyGon
Copy link
Member

LazyGon commented Feb 1, 2023

ちなみに上に上がってるデータベーススキーマはWIP

概ね賛成

カスタム名やアイテムを持ってるなど、単にスポーンした状態と違うエンティティのみ NBT を保存するようにしたい。

それぞれで当然に違うデータ、例えばUUIDとかkeepalive、posなんかの情報を消すようにして、データベースに同じエンティティがいたらidを流用すれば効率的かもしれない
co_blockもそのように同じステート、データのブロックなら複数のlogでid指定して流用したいところ

co_world - ワールド名ではなくネームスペースで管理するべき?

となると、materialを消してnamespacesテーブルを作り、保存したネームスペースをblockとworldテーブルで共有する?

co_container などのコンテナ操作はどのテーブルで行う?

迷いどころ
普通にcontainerテーブル作るのが妥当か

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants