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

PostgreSQLにする #4534

Closed
syuilo opened this issue Mar 19, 2019 · 52 comments · Fixed by #4572
Closed

PostgreSQLにする #4534

syuilo opened this issue Mar 19, 2019 · 52 comments · Fixed by #4572
Assignees
Labels
☢️Breaking This change breaks compatibility 💬Discussion Being discussed or needs discussion ✨Feature This adds/improves/enhances a feature packages/backend Server side specific issue/PR

Comments

@syuilo
Copy link
Member

syuilo commented Mar 19, 2019

Summary

  • MongoDBでしか出来ないようなことはほとんどしていない
  • Misskeyで扱うほとんどのデータはきっちりとスキーマが決まっていてリレーショナルなので、リレーショナルデータベースの方が都合が良い
  • 親レコードが削除されたら子レコードも自動的に削除、とかできるので削除系の処理の実装が簡単になりそう
  • プログラム上でObjectIDをいちいち変換するのがめんどい
  • MongoDBはPostgreSQLと比較するとメジャーでない

Related to #3510, #4203

Working on https://github.com/syuilo/misskey/tree/pg

メモ

  • インスタンスをブロックしているかどうかはインスタンステーブルには保存しないでinstanceBlockingなどのテーブルに別途保存する
  • オブジェクトストレージを使用しない場合、ファイルをデータベースに保存するのはやめてサーバーのファイルシステム上に保存するようにする
  • Metaに投稿数などを保存するのをやめる(必要ならその都度カウントする)
  • MongoDBでは重複レコードエラーは e.code === 11000 で判別できたけどPostgreSQLの場合どうなるのか
  • 壁紙設定はクライアントの設定に移動
  • getDriveFileUrl --> getThumbnailUrl に
  • pinnedNoteIds は廃止して userNotePinings といったテーブルを作る
  • 正規表現検索をする方法
  • 配列に値を追加する方法
  • simple-array ではなく array: true を使用
  • 投稿に _files として添付ファイルを非正規化するのをやめる
    • というか isAttachingSensitiveFiles と attachedFileTypes みたいな非正規化プロパティに分解する
  • _reply _renote _user といった非正規化プロパティも replyUserId replyUserHost renoteUserId renoteUserHost userHost userInbox みたいに分割
  • ホームのカスタマイズ情報をサーバーに保存するのをやめる
@syuilo syuilo added ✨Feature This adds/improves/enhances a feature packages/backend Server side specific issue/PR ☢️Breaking This change breaks compatibility labels Mar 19, 2019
@syuilo syuilo self-assigned this Mar 19, 2019
@acid-chicken
Copy link
Member

大変そう。手伝えることがあったら言ってください。

@syuilo
Copy link
Member Author

syuilo commented Mar 19, 2019

ありがとうございます!
一部で行っている複雑なクエリをPostgreSQLで実現できるかなど分からない部分もありますが頑張ります

@acid-chicken
Copy link
Member

ちなみに何を使うとかいう具体的な方針は決まってたりしますか?

@syuilo
Copy link
Member Author

syuilo commented Mar 19, 2019

PostgreSQLの具体的なバージョンはまだ未定ですがORMはtypeormの予定です

@syuilo
Copy link
Member Author

syuilo commented Mar 19, 2019

pgブランチ作りました。
まずモデル定義(src/models)をtypeormを使用したものに書き換えていく必要があります。例はここら辺に
時間のある方はこの作業に参加していただけると助かります

@syuilo syuilo pinned this issue Mar 19, 2019
@syuilo
Copy link
Member Author

syuilo commented Mar 19, 2019

外部キー制約って配列には適用できない...?
例えば投稿の添付された複数のファイルを表すfileIdsとか

@syuilo
Copy link
Member Author

syuilo commented Mar 19, 2019

noteFileAttachment といった別のテーブル作るしかないか

@syuilo
Copy link
Member Author

syuilo commented Mar 20, 2019

renoteCount とか repliesCount とか reactionCounts とか保存すべき?
これらのカラムはすべて非正規化されてるようなもので、これらが無くても理論的にはその投稿のRenote数や返信数やリアクション数は取得できる

@syuilo syuilo added 🏳️Needs help 💬Discussion Being discussed or needs discussion labels Mar 20, 2019
@syuilo
Copy link
Member Author

syuilo commented Mar 20, 2019

とりあえず無くしといてパフォーマンス上の問題があるようなら非正規化でも良いかもしれないけど後から設計を変えるのもそれはそれで面倒

@syuilo
Copy link
Member Author

syuilo commented Mar 20, 2019

visibleUserIds も外部キーの配列だけど、さすがにこれのためだけにテーブル作るのはなんかアレ
不通に数値(ID)の配列として保存するか...

@syuilo
Copy link
Member Author

syuilo commented Mar 20, 2019

んーでも、自分宛てのダイレクト投稿を一覧取得するケースもあるか...

@mei23
Copy link
Contributor

mei23 commented Mar 20, 2019

renoteCount とか repliesCount とか reactionCounts とか保存すべき?

renoteCount (APIではnumber) 保存する
repliesCount (APIではnumber) 保存する
reactionCounts (APIではObject) 必ずNoteReactionsみたいなテーブルを見るとおもうので保存しない
とか?

@syuilo
Copy link
Member Author

syuilo commented Mar 20, 2019

ありがとうございます

必ずNoteReactionsみたいなテーブルを見るとおもう

んー、そんなことないかも

@mei23
Copy link
Contributor

mei23 commented Mar 20, 2019

んー、そんなことないかも

JSON? 今みたいにNoteReactionを使うのかと…
あれ、今NoteReactioninsertしかしてない

@syuilo
Copy link
Member Author

syuilo commented Mar 20, 2019

typeormはやめてsequelize-typescriptにします

@acid-chicken
Copy link
Member

TypeORM 評判悪いと聞いていたので正直ほっとしました。

@syuilo
Copy link
Member Author

syuilo commented Mar 20, 2019

個々のIDが変わっても問題ないならばマイグレ用意することはできる
ただ大変という問題はあるけど

@syuilo
Copy link
Member Author

syuilo commented Mar 20, 2019

ユーザーに関しては、IDが比較可能である必要はない(ランダムな文字列で問題ない)ため、マイグレの際は以前のObjectIDをそのまま引き継ぐことが可能そう

@mei23
Copy link
Contributor

mei23 commented Mar 21, 2019

現在のIDについては
https://docs.mongodb.com/manual/reference/method/ObjectId/

日付が含まれているものの、生成時期を考えると (上位4ビットが0になった時期がないので)
事実上固定長 (24文字hex文字列) なので比較可能だと思います。

また、現在のIDは上位の方のビットが0101までのIDが採番されているので
新たに1xxxなど最上位ビットが埋まっているIDなどを採番すれば重複することもないのではと思います。

@tamaina
Copy link
Contributor

tamaina commented Mar 21, 2019

そういえば: PostgreSQLになったらElasticSearchではなくなる?

@syuilo
Copy link
Member Author

syuilo commented Mar 21, 2019

sequelize-typescript は ActiveRecord しかできなくて微妙

@acid-chicken
Copy link
Member

PeerTube の開発者の方々にお伺いをたてるのも手かと。

@syuilo
Copy link
Member Author

syuilo commented Mar 21, 2019

Misskeyはデータベースから取得したレコードはすぐレスポンスとして返す場合がほとんど(いじくったりしない)ので、レコード自体にメソッドがあっても意味ないし、いちいちインスタンス化するコストもかかる
ORMによっては取得時にインスタンス化しないオプションを提供するものもあるけど、ほぼすべての find 時にそのオプションを true にするのは面倒すぎる

@syuilo
Copy link
Member Author

syuilo commented Mar 22, 2019

v10時点でのデータベースの設計や命名などで気になっている点がある方は今のうちに言っておいてください

@syuilo
Copy link
Member Author

syuilo commented Mar 22, 2019

20%くらい終わった

@syuilo
Copy link
Member Author

syuilo commented Mar 23, 2019

ついでに #4018 もやる

@syuilo
Copy link
Member Author

syuilo commented Mar 23, 2019

型定義は作らないかもしれないけど、「不要な値を削除」方式ではなくこんな感じに「必要な値をコピー」する感じ
https://github.com/syuilo/misskey/blob/578143096f1accdc7e23a72b2cbe76768969d1f4/src/models/repositories/user.ts#L48-L84

@syuilo
Copy link
Member Author

syuilo commented Mar 23, 2019

型定義作るとしたら、せっかく作っても型定義とドキュメントが一致していないということが起こり得るので、ドキュメントから型定義を自動生成するようにする
それなら型定義とドキュメントが必ず一致することが保証される

@syuilo
Copy link
Member Author

syuilo commented Mar 23, 2019

今はAPIのパラメータの型情報はドキュメント(cafy定義)から自動生成している状態なのでそれと同じ感じで

@mei23
Copy link
Contributor

mei23 commented Mar 23, 2019

modelのリファクタ系developとかv10なんたらとかのブランチにマージしておきたい気がします

@mei23
Copy link
Contributor

mei23 commented Mar 23, 2019

↑今はmodel配下のマッピングの差分がわからなくなってしまったので

@syuilo
Copy link
Member Author

syuilo commented Mar 23, 2019

今まで models にあったものは models/entities と models/repositories に分割されました
entiriesにはスキーマ定義だけあって、repositoriesにはそのスキーマに属するメソッドが定義されます

例えば今までこのように書いていたものはこうなります

before

import Note, { INote, pack } from './models/note';

const foo: INote = bar();
const note = Note.findOne({ _id: x });
return pack(note);

after

import { Note } from './models/entities/note';
import { Notes } from './models';

const foo: Note = bar();
const note = Notes.findOne(x);
return Notes.pack(note);

@syuilo
Copy link
Member Author

syuilo commented Mar 23, 2019

entity と repository を区別するために、上の例にあるように repository の方は複数形になってます
Note が entity で Notes が NoteのRepostiry

@syuilo
Copy link
Member Author

syuilo commented Mar 23, 2019

entity は、上述のようにスキーマ定義であってメソッドなどは何も持ってないので、コード上で entity を使うのは型注釈のためだけになると思います
repository は実際にデータベースからデータを持ってきたり更新したりなどのいろいろなメソッドを持っているので頻繁に使います

@syuilo
Copy link
Member Author

syuilo commented Mar 24, 2019

30%くらい終わった

@syuilo
Copy link
Member Author

syuilo commented Mar 25, 2019

各種IDにULIDを使おうと思うんですけどどう思いますか?
IDが数値だと、例えばアクセスされたURLに含まれているIDを元にデータベースに問い合わせるようなシナリオで、プログラム上でいちいち文字列から数値に変換する必要があってめんどい

@mei23
Copy link
Contributor

mei23 commented Mar 25, 2019

@syuilo
noteIdとかuserIdでもULIDにして、既存IDとの連続性とかは考慮しない感じでしょうか?

@syuilo
Copy link
Member Author

syuilo commented Mar 25, 2019

う~~~む

@syuilo
Copy link
Member Author

syuilo commented Mar 25, 2019

ランダムではないので連続性は保たれそう

@syuilo
Copy link
Member Author

syuilo commented Mar 25, 2019

ちゃんと元の順番通りinsertしていけば

@syuilo
Copy link
Member Author

syuilo commented Mar 25, 2019

ULIDほどのユニークさは求めてないのでULIDをちょっと改造したものになりそう

@mei23
Copy link
Contributor

mei23 commented Mar 25, 2019

そもそもnoteIdとかuserIdって (同じIDで) 移行しますか?
Hex 24文字 => Base32 26文字 にするということは移行なしですかね?

@syuilo
Copy link
Member Author

syuilo commented Mar 25, 2019

IDは変わると考えてます

@mei23
Copy link
Contributor

mei23 commented Mar 25, 2019

ID変えてしまうとユーザー移行が難しくなるのではと思います (AP的に)

@syuilo
Copy link
Member Author

syuilo commented Mar 25, 2019

こまこまのこまり

@mei23
Copy link
Contributor

mei23 commented Mar 25, 2019

  • (固定値1 1bit) + (Timestamp 47bits UNIX ms) + Random 48bits = 96bits (12Bytes, 24 Hex chars)
  • エンコードはHex

にすれば旧IDと重複しないので旧IDがそのまま使えて
順番も旧ID→新IDとつながると思います

@fz0000
Copy link
Contributor

fz0000 commented Apr 3, 2019

So is there any plan to support other databases?
Database server is much cheaper than VPS. But not all ISPs provide MongoDB(or even PostgreSQL)... (MySQL and MS SQL Server are most widely used) If I were building my own site, I would like to just buy a database server instead of a VPS that I need to install MondoDB myself. 😄

@syuilo
Copy link
Member Author

syuilo commented Apr 3, 2019

Support is difficult because MySQL doesn't support arrays or JSON columns.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
☢️Breaking This change breaks compatibility 💬Discussion Being discussed or needs discussion ✨Feature This adds/improves/enhances a feature packages/backend Server side specific issue/PR
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants