[bugfix] fix slow accounts / statuses using emojis lookups (#2056)
* update DeleteEmoji to use faster relational tables for status / account finding Signed-off-by: kim <grufwub@gmail.com> * update Get{Accounts,Statuses}UsingEmoji() to also use relational tables Signed-off-by: kim <grufwub@gmail.com> * remove the now unneeded tags relation from newStatusQ() Signed-off-by: kim <grufwub@gmail.com> * fix table names Signed-off-by: kim <grufwub@gmail.com> * fix account and status selects using emojis Signed-off-by: kim <grufwub@gmail.com> --------- Signed-off-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
24516b84c2
commit
2cee8f2dd8
|
@ -468,24 +468,13 @@ func (a *accountDB) GetAccountCustomCSSByUsername(ctx context.Context, username
|
||||||
func (a *accountDB) GetAccountsUsingEmoji(ctx context.Context, emojiID string) ([]*gtsmodel.Account, error) {
|
func (a *accountDB) GetAccountsUsingEmoji(ctx context.Context, emojiID string) ([]*gtsmodel.Account, error) {
|
||||||
var accountIDs []string
|
var accountIDs []string
|
||||||
|
|
||||||
// Create SELECT account query.
|
// SELECT all accounts using this emoji,
|
||||||
q := a.db.NewSelect().
|
// using a relational table for improved perf.
|
||||||
Table("accounts").
|
if _, err := a.db.NewSelect().
|
||||||
Column("id")
|
Table("account_to_emojis").
|
||||||
|
Column("account_id").
|
||||||
// Append a WHERE LIKE clause to the query
|
Where("? = ?", bun.Ident("emoji_id"), emojiID).
|
||||||
// that checks the `emoji` column for any
|
Exec(ctx, &accountIDs); err != nil {
|
||||||
// text containing this specific emoji ID.
|
|
||||||
//
|
|
||||||
// The reason we do this instead of doing a
|
|
||||||
// `WHERE ? IN (emojis)` is that the latter
|
|
||||||
// ends up being much MUCH slower, and the
|
|
||||||
// database stores this ID-array-column as
|
|
||||||
// text anyways, allowing a simple LIKE query.
|
|
||||||
q = whereLike(q, "emojis", emojiID)
|
|
||||||
|
|
||||||
// Execute the query, scanning destination into accountIDs.
|
|
||||||
if _, err := q.Exec(ctx, &accountIDs); err != nil {
|
|
||||||
return nil, a.db.ProcessError(err)
|
return nil, a.db.ProcessError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,76 +106,25 @@ func (e *emojiDB) DeleteEmojiByID(ctx context.Context, id string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.db.RunInTx(ctx, func(tx bun.Tx) error {
|
return e.db.RunInTx(ctx, func(tx bun.Tx) error {
|
||||||
// delete links between this emoji and any statuses that use it
|
// Delete relational links between this emoji
|
||||||
// TODO: remove when we delete this table
|
// and any statuses using it, returning the
|
||||||
if _, err := tx.
|
// status IDs so we can later update them.
|
||||||
NewDelete().
|
if _, err := tx.NewDelete().
|
||||||
TableExpr("? AS ?", bun.Ident("status_to_emojis"), bun.Ident("status_to_emoji")).
|
Table("status_to_emojis").
|
||||||
Where("? = ?", bun.Ident("status_to_emoji.emoji_id"), id).
|
Where("? = ?", bun.Ident("emoji_id"), id).
|
||||||
Exec(ctx); err != nil {
|
Returning("status_id").
|
||||||
|
Exec(ctx, &statusIDs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete links between this emoji and any accounts that use it
|
// Delete relational links between this emoji
|
||||||
// TODO: remove when we delete this table
|
// and any accounts using it, returning the
|
||||||
if _, err := tx.
|
// account IDs so we can later update them.
|
||||||
NewDelete().
|
if _, err := tx.NewDelete().
|
||||||
TableExpr("? AS ?", bun.Ident("account_to_emojis"), bun.Ident("account_to_emoji")).
|
Table("account_to_emojis").
|
||||||
Where("? = ?", bun.Ident("account_to_emoji.emoji_id"), id).
|
Where("? = ?", bun.Ident("emoji_id"), id).
|
||||||
Exec(ctx); err != nil {
|
Returning("account_id").
|
||||||
return err
|
Exec(ctx, &accountIDs); err != nil {
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare a SELECT query with a WHERE LIKE
|
|
||||||
// that checks the `emoji` column for any
|
|
||||||
// text containing this specific emoji ID.
|
|
||||||
//
|
|
||||||
// (see GetStatusesUsingEmoji() for details.)
|
|
||||||
aq := tx.NewSelect().Table("accounts").Column("id")
|
|
||||||
aq = whereLike(aq, "emojis", id)
|
|
||||||
|
|
||||||
// Select all accounts using this emoji into accountIDss.
|
|
||||||
if _, err := aq.Exec(ctx, &accountIDs); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, id := range accountIDs {
|
|
||||||
var emojiIDs []string
|
|
||||||
|
|
||||||
// Select account with ID.
|
|
||||||
if _, err := tx.NewSelect().
|
|
||||||
Table("accounts").
|
|
||||||
Column("emojis").
|
|
||||||
Where("id = ?", id).
|
|
||||||
Exec(ctx); err != nil &&
|
|
||||||
err != sql.ErrNoRows {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drop ID from account emojis.
|
|
||||||
emojiIDs = dropID(emojiIDs, id)
|
|
||||||
|
|
||||||
// Update account emoji IDs.
|
|
||||||
if _, err := tx.NewUpdate().
|
|
||||||
Table("accounts").
|
|
||||||
Where("id = ?", id).
|
|
||||||
Set("emojis = ?", emojiIDs).
|
|
||||||
Exec(ctx); err != nil &&
|
|
||||||
err != sql.ErrNoRows {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare a SELECT query with a WHERE LIKE
|
|
||||||
// that checks the `emoji` column for any
|
|
||||||
// text containing this specific emoji ID.
|
|
||||||
//
|
|
||||||
// (see GetStatusesUsingEmoji() for details.)
|
|
||||||
sq := tx.NewSelect().Table("statuses").Column("id")
|
|
||||||
sq = whereLike(sq, "emojis", id)
|
|
||||||
|
|
||||||
// Select all statuses using this emoji into statusIDs.
|
|
||||||
if _, err := sq.Exec(ctx, &statusIDs); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +135,7 @@ func (e *emojiDB) DeleteEmojiByID(ctx context.Context, id string) error {
|
||||||
if _, err := tx.NewSelect().
|
if _, err := tx.NewSelect().
|
||||||
Table("statuses").
|
Table("statuses").
|
||||||
Column("emojis").
|
Column("emojis").
|
||||||
Where("id = ?", id).
|
Where("? = ?", bun.Ident("id"), id).
|
||||||
Exec(ctx); err != nil &&
|
Exec(ctx); err != nil &&
|
||||||
err != sql.ErrNoRows {
|
err != sql.ErrNoRows {
|
||||||
return err
|
return err
|
||||||
|
@ -198,7 +147,34 @@ func (e *emojiDB) DeleteEmojiByID(ctx context.Context, id string) error {
|
||||||
// Update status emoji IDs.
|
// Update status emoji IDs.
|
||||||
if _, err := tx.NewUpdate().
|
if _, err := tx.NewUpdate().
|
||||||
Table("statuses").
|
Table("statuses").
|
||||||
Where("id = ?", id).
|
Where("? = ?", bun.Ident("id"), id).
|
||||||
|
Set("emojis = ?", emojiIDs).
|
||||||
|
Exec(ctx); err != nil &&
|
||||||
|
err != sql.ErrNoRows {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, id := range accountIDs {
|
||||||
|
var emojiIDs []string
|
||||||
|
|
||||||
|
// Select account with ID.
|
||||||
|
if _, err := tx.NewSelect().
|
||||||
|
Table("accounts").
|
||||||
|
Column("emojis").
|
||||||
|
Where("? = ?", bun.Ident("id"), id).
|
||||||
|
Exec(ctx); err != nil &&
|
||||||
|
err != sql.ErrNoRows {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop ID from account emojis.
|
||||||
|
emojiIDs = dropID(emojiIDs, id)
|
||||||
|
|
||||||
|
// Update account emoji IDs.
|
||||||
|
if _, err := tx.NewUpdate().
|
||||||
|
Table("accounts").
|
||||||
|
Where("? = ?", bun.Ident("id"), id).
|
||||||
Set("emojis = ?", emojiIDs).
|
Set("emojis = ?", emojiIDs).
|
||||||
Exec(ctx); err != nil &&
|
Exec(ctx); err != nil &&
|
||||||
err != sql.ErrNoRows {
|
err != sql.ErrNoRows {
|
||||||
|
@ -209,7 +185,7 @@ func (e *emojiDB) DeleteEmojiByID(ctx context.Context, id string) error {
|
||||||
// Delete emoji from database.
|
// Delete emoji from database.
|
||||||
if _, err := tx.NewDelete().
|
if _, err := tx.NewDelete().
|
||||||
Table("emojis").
|
Table("emojis").
|
||||||
Where("id = ?", id).
|
Where("? = ?", bun.Ident("id"), id).
|
||||||
Exec(ctx); err != nil {
|
Exec(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,6 @@ func (s *statusDB) newStatusQ(status interface{}) *bun.SelectQuery {
|
||||||
return s.db.
|
return s.db.
|
||||||
NewSelect().
|
NewSelect().
|
||||||
Model(status).
|
Model(status).
|
||||||
Relation("Tags").
|
|
||||||
Relation("CreatedWithApplication")
|
Relation("CreatedWithApplication")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,24 +439,13 @@ func (s *statusDB) DeleteStatusByID(ctx context.Context, id string) error {
|
||||||
func (s *statusDB) GetStatusesUsingEmoji(ctx context.Context, emojiID string) ([]*gtsmodel.Status, error) {
|
func (s *statusDB) GetStatusesUsingEmoji(ctx context.Context, emojiID string) ([]*gtsmodel.Status, error) {
|
||||||
var statusIDs []string
|
var statusIDs []string
|
||||||
|
|
||||||
// Create SELECT status query.
|
// SELECT all statuses using this emoji,
|
||||||
q := s.db.NewSelect().
|
// using a relational table for improved perf.
|
||||||
Table("statuses").
|
if _, err := s.db.NewSelect().
|
||||||
Column("id")
|
Table("status_to_emojis").
|
||||||
|
Column("status_id").
|
||||||
// Append a WHERE LIKE clause to the query
|
Where("? = ?", bun.Ident("emoji_id"), emojiID).
|
||||||
// that checks the `emoji` column for any
|
Exec(ctx, &statusIDs); err != nil {
|
||||||
// text containing this specific emoji ID.
|
|
||||||
//
|
|
||||||
// The reason we do this instead of doing a
|
|
||||||
// `WHERE ? IN (emojis)` is that the latter
|
|
||||||
// ends up being much MUCH slower, and the
|
|
||||||
// database stores this ID-array-column as
|
|
||||||
// text anyways, allowing a simple LIKE query.
|
|
||||||
q = whereLike(q, "emojis", emojiID)
|
|
||||||
|
|
||||||
// Execute the query, scanning destination into statusIDs.
|
|
||||||
if _, err := q.Exec(ctx, &statusIDs); err != nil {
|
|
||||||
return nil, s.db.ProcessError(err)
|
return nil, s.db.ProcessError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue