mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 23:12:25 -05:00 
			
		
		
		
	[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
					
				
			
		
					 3 changed files with 60 additions and 107 deletions
				
			
		|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue