MM-45956: Optimize FileInfo stats query (#22603)
* MM-45956: Optimize FileInfo stats query We Denormalize Post.ChannelId on FileInfo.ChannelId ```release-note The file info stats query is now optimized by denormalizing the channelID column into the table itself. This will speed up the query to get the file count for a channel on clicking the RHS. Migration times: On a MySQL 8.0.31 DB with 1405 rows in FileInfo and 11M posts, it took around 0.3s On a Postgres 12.14 DB with 1731 rows in FileInfo and 11M posts, it took around 0.27s ``` https://mattermost.atlassian.net/browse/MM-45956
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
1edbde8aa3
Коммит
56b18ca7bf
@@ -106,26 +106,31 @@ func testFileInfoSaveGetByPath(t *testing.T, ss store.Store) {
|
||||
func testFileInfoGetForPost(t *testing.T, ss store.Store) {
|
||||
userId := model.NewId()
|
||||
postId := model.NewId()
|
||||
channelId := model.NewId()
|
||||
|
||||
infos := []*model.FileInfo{
|
||||
{
|
||||
PostId: postId,
|
||||
ChannelId: channelId,
|
||||
CreatorId: userId,
|
||||
Path: "file.txt",
|
||||
},
|
||||
{
|
||||
PostId: postId,
|
||||
ChannelId: channelId,
|
||||
CreatorId: userId,
|
||||
Path: "file.txt",
|
||||
},
|
||||
{
|
||||
PostId: postId,
|
||||
ChannelId: channelId,
|
||||
CreatorId: userId,
|
||||
Path: "file.txt",
|
||||
DeleteAt: 123,
|
||||
},
|
||||
{
|
||||
PostId: model.NewId(),
|
||||
ChannelId: channelId,
|
||||
CreatorId: userId,
|
||||
Path: "file.txt",
|
||||
},
|
||||
@@ -225,25 +230,30 @@ func testFileInfoGetForUser(t *testing.T, ss store.Store) {
|
||||
userId := model.NewId()
|
||||
userId2 := model.NewId()
|
||||
postId := model.NewId()
|
||||
channelId := model.NewId()
|
||||
|
||||
infos := []*model.FileInfo{
|
||||
{
|
||||
PostId: postId,
|
||||
ChannelId: channelId,
|
||||
CreatorId: userId,
|
||||
Path: "file.txt",
|
||||
},
|
||||
{
|
||||
PostId: postId,
|
||||
ChannelId: channelId,
|
||||
CreatorId: userId,
|
||||
Path: "file.txt",
|
||||
},
|
||||
{
|
||||
PostId: postId,
|
||||
ChannelId: channelId,
|
||||
CreatorId: userId,
|
||||
Path: "file.txt",
|
||||
},
|
||||
{
|
||||
PostId: model.NewId(),
|
||||
ChannelId: channelId,
|
||||
CreatorId: userId2,
|
||||
Path: "file.txt",
|
||||
},
|
||||
@@ -289,6 +299,9 @@ func testFileInfoGetWithOptions(t *testing.T, ss store.Store) {
|
||||
if post.Id != "" {
|
||||
fileInfo.PostId = post.Id
|
||||
}
|
||||
if post.ChannelId != "" {
|
||||
fileInfo.ChannelId = post.ChannelId
|
||||
}
|
||||
_, err := ss.FileInfo().Save(&fileInfo)
|
||||
require.NoError(t, err)
|
||||
return fileInfo
|
||||
@@ -414,6 +427,7 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) {
|
||||
t.Run("should attach files", func(t *testing.T) {
|
||||
userId := model.NewId()
|
||||
postId := model.NewId()
|
||||
channelId := model.NewId()
|
||||
|
||||
info1, err := ss.FileInfo().Save(&model.FileInfo{
|
||||
CreatorId: userId,
|
||||
@@ -429,13 +443,15 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) {
|
||||
require.Equal(t, "", info1.PostId)
|
||||
require.Equal(t, "", info2.PostId)
|
||||
|
||||
err = ss.FileInfo().AttachToPost(info1.Id, postId, userId)
|
||||
err = ss.FileInfo().AttachToPost(info1.Id, postId, channelId, userId)
|
||||
assert.NoError(t, err)
|
||||
info1.PostId = postId
|
||||
info1.ChannelId = channelId
|
||||
|
||||
err = ss.FileInfo().AttachToPost(info2.Id, postId, userId)
|
||||
err = ss.FileInfo().AttachToPost(info2.Id, postId, channelId, userId)
|
||||
assert.NoError(t, err)
|
||||
info2.PostId = postId
|
||||
info2.ChannelId = channelId
|
||||
|
||||
data, err := ss.FileInfo().GetForPost(postId, true, false, false)
|
||||
require.NoError(t, err)
|
||||
@@ -449,6 +465,7 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) {
|
||||
t.Run("should not attach files to multiple posts", func(t *testing.T) {
|
||||
userId := model.NewId()
|
||||
postId := model.NewId()
|
||||
channelId := model.NewId()
|
||||
|
||||
info, err := ss.FileInfo().Save(&model.FileInfo{
|
||||
CreatorId: userId,
|
||||
@@ -458,16 +475,17 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) {
|
||||
|
||||
require.Equal(t, "", info.PostId)
|
||||
|
||||
err = ss.FileInfo().AttachToPost(info.Id, model.NewId(), userId)
|
||||
err = ss.FileInfo().AttachToPost(info.Id, model.NewId(), channelId, userId)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ss.FileInfo().AttachToPost(info.Id, postId, userId)
|
||||
err = ss.FileInfo().AttachToPost(info.Id, postId, channelId, userId)
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("should not attach files owned from a different user", func(t *testing.T) {
|
||||
userId := model.NewId()
|
||||
postId := model.NewId()
|
||||
channelId := model.NewId()
|
||||
|
||||
info, err := ss.FileInfo().Save(&model.FileInfo{
|
||||
CreatorId: model.NewId(),
|
||||
@@ -477,12 +495,13 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) {
|
||||
|
||||
require.Equal(t, "", info.PostId)
|
||||
|
||||
err = ss.FileInfo().AttachToPost(info.Id, postId, userId)
|
||||
err = ss.FileInfo().AttachToPost(info.Id, postId, channelId, userId)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("should attach files uploaded by nouser", func(t *testing.T) {
|
||||
postId := model.NewId()
|
||||
channelId := model.NewId()
|
||||
|
||||
info, err := ss.FileInfo().Save(&model.FileInfo{
|
||||
CreatorId: "nouser",
|
||||
@@ -491,12 +510,13 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "", info.PostId)
|
||||
|
||||
err = ss.FileInfo().AttachToPost(info.Id, postId, model.NewId())
|
||||
err = ss.FileInfo().AttachToPost(info.Id, postId, channelId, model.NewId())
|
||||
require.NoError(t, err)
|
||||
|
||||
data, err := ss.FileInfo().GetForPost(postId, true, false, false)
|
||||
require.NoError(t, err)
|
||||
info.PostId = postId
|
||||
info.ChannelId = channelId
|
||||
assert.EqualValues(t, []*model.FileInfo{info}, data)
|
||||
})
|
||||
}
|
||||
@@ -504,26 +524,31 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) {
|
||||
func testFileInfoDeleteForPost(t *testing.T, ss store.Store) {
|
||||
userId := model.NewId()
|
||||
postId := model.NewId()
|
||||
channelId := model.NewId()
|
||||
|
||||
infos := []*model.FileInfo{
|
||||
{
|
||||
PostId: postId,
|
||||
ChannelId: channelId,
|
||||
CreatorId: userId,
|
||||
Path: "file.txt",
|
||||
},
|
||||
{
|
||||
PostId: postId,
|
||||
ChannelId: channelId,
|
||||
CreatorId: userId,
|
||||
Path: "file.txt",
|
||||
},
|
||||
{
|
||||
PostId: postId,
|
||||
ChannelId: channelId,
|
||||
CreatorId: userId,
|
||||
Path: "file.txt",
|
||||
DeleteAt: 123,
|
||||
},
|
||||
{
|
||||
PostId: model.NewId(),
|
||||
ChannelId: channelId,
|
||||
CreatorId: userId,
|
||||
Path: "file.txt",
|
||||
},
|
||||
@@ -549,6 +574,7 @@ func testFileInfoDeleteForPost(t *testing.T, ss store.Store) {
|
||||
func testFileInfoPermanentDelete(t *testing.T, ss store.Store) {
|
||||
info, err := ss.FileInfo().Save(&model.FileInfo{
|
||||
PostId: model.NewId(),
|
||||
ChannelId: model.NewId(),
|
||||
CreatorId: model.NewId(),
|
||||
Path: "file.txt",
|
||||
})
|
||||
@@ -560,9 +586,11 @@ func testFileInfoPermanentDelete(t *testing.T, ss store.Store) {
|
||||
|
||||
func testFileInfoPermanentDeleteBatch(t *testing.T, ss store.Store) {
|
||||
postId := model.NewId()
|
||||
channelId := model.NewId()
|
||||
|
||||
_, err := ss.FileInfo().Save(&model.FileInfo{
|
||||
PostId: postId,
|
||||
ChannelId: channelId,
|
||||
CreatorId: model.NewId(),
|
||||
Path: "file.txt",
|
||||
CreateAt: 1000,
|
||||
@@ -571,6 +599,7 @@ func testFileInfoPermanentDeleteBatch(t *testing.T, ss store.Store) {
|
||||
|
||||
_, err = ss.FileInfo().Save(&model.FileInfo{
|
||||
PostId: postId,
|
||||
ChannelId: channelId,
|
||||
CreatorId: model.NewId(),
|
||||
Path: "file.txt",
|
||||
CreateAt: 1200,
|
||||
@@ -579,6 +608,7 @@ func testFileInfoPermanentDeleteBatch(t *testing.T, ss store.Store) {
|
||||
|
||||
_, err = ss.FileInfo().Save(&model.FileInfo{
|
||||
PostId: postId,
|
||||
ChannelId: channelId,
|
||||
CreatorId: model.NewId(),
|
||||
Path: "file.txt",
|
||||
CreateAt: 2000,
|
||||
@@ -600,9 +630,11 @@ func testFileInfoPermanentDeleteBatch(t *testing.T, ss store.Store) {
|
||||
func testFileInfoPermanentDeleteByUser(t *testing.T, ss store.Store) {
|
||||
userId := model.NewId()
|
||||
postId := model.NewId()
|
||||
channelId := model.NewId()
|
||||
|
||||
_, err := ss.FileInfo().Save(&model.FileInfo{
|
||||
PostId: postId,
|
||||
ChannelId: channelId,
|
||||
CreatorId: userId,
|
||||
Path: "file.txt",
|
||||
})
|
||||
@@ -668,6 +700,7 @@ func testFileInfoStoreGetFilesBatchForIndexing(t *testing.T, ss store.Store) {
|
||||
require.NoError(t, err)
|
||||
f1, err := ss.FileInfo().Save(&model.FileInfo{
|
||||
PostId: o1.Id,
|
||||
ChannelId: o1.ChannelId,
|
||||
CreatorId: model.NewId(),
|
||||
Path: "file1.txt",
|
||||
})
|
||||
@@ -686,6 +719,7 @@ func testFileInfoStoreGetFilesBatchForIndexing(t *testing.T, ss store.Store) {
|
||||
|
||||
f2, err := ss.FileInfo().Save(&model.FileInfo{
|
||||
PostId: o2.Id,
|
||||
ChannelId: o2.ChannelId,
|
||||
CreatorId: model.NewId(),
|
||||
Path: "file2.txt",
|
||||
})
|
||||
@@ -705,6 +739,7 @@ func testFileInfoStoreGetFilesBatchForIndexing(t *testing.T, ss store.Store) {
|
||||
|
||||
f3, err := ss.FileInfo().Save(&model.FileInfo{
|
||||
PostId: o3.Id,
|
||||
ChannelId: o3.ChannelId,
|
||||
CreatorId: model.NewId(),
|
||||
Path: "file3.txt",
|
||||
})
|
||||
@@ -737,6 +772,7 @@ func testFileInfoStoreCountAll(t *testing.T, ss store.Store) {
|
||||
require.NoError(t, err)
|
||||
f1, err := ss.FileInfo().Save(&model.FileInfo{
|
||||
PostId: model.NewId(),
|
||||
ChannelId: model.NewId(),
|
||||
CreatorId: model.NewId(),
|
||||
Path: "file1.txt",
|
||||
})
|
||||
@@ -744,12 +780,14 @@ func testFileInfoStoreCountAll(t *testing.T, ss store.Store) {
|
||||
|
||||
_, err = ss.FileInfo().Save(&model.FileInfo{
|
||||
PostId: model.NewId(),
|
||||
ChannelId: model.NewId(),
|
||||
CreatorId: model.NewId(),
|
||||
Path: "file2.txt",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = ss.FileInfo().Save(&model.FileInfo{
|
||||
PostId: model.NewId(),
|
||||
ChannelId: model.NewId(),
|
||||
CreatorId: model.NewId(),
|
||||
Path: "file3.txt",
|
||||
})
|
||||
|
||||
@@ -14,13 +14,13 @@ type FileInfoStore struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// AttachToPost provides a mock function with given fields: fileID, postID, creatorID
|
||||
func (_m *FileInfoStore) AttachToPost(fileID string, postID string, creatorID string) error {
|
||||
ret := _m.Called(fileID, postID, creatorID)
|
||||
// AttachToPost provides a mock function with given fields: fileID, postID, channelID, creatorID
|
||||
func (_m *FileInfoStore) AttachToPost(fileID string, postID string, channelID string, creatorID string) error {
|
||||
ret := _m.Called(fileID, postID, channelID, creatorID)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, string, string) error); ok {
|
||||
r0 = rf(fileID, postID, creatorID)
|
||||
if rf, ok := ret.Get(0).(func(string, string, string, string) error); ok {
|
||||
r0 = rf(fileID, postID, channelID, creatorID)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user