gitlab-org--gitlab-foss/app/models/lfs_object.rb
Toon Claes d5f290e417 Enhance performance of counting local LFS objects
Add an index to the `file_store` column on `lfs_objects`. This makes
counting local objects faster.

Also, there is no longer need to check for objects with `file_store`
being `NULL`. See
https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18557

---

### Query plans

#### Before & with `NULL`

```
Aggregate  (cost=113495.96..113495.97 rows=1 width=8) (actual time=1691.394..1691.394 rows=1 loops=1)
  ->  Seq Scan on lfs_objects  (cost=0.00..106415.50 rows=2832186 width=0) (actual time=0.012..1312.488 rows=2852607 loops=1)
        Filter: ((file_store = 1) OR (file_store IS NULL))
        Rows Removed by Filter: 131
Planning time: 0.077 ms
Execution time: 1691.433 ms
```

#### Before, without `NULL`

```
Aggregate  (cost=113495.96..113495.97 rows=1 width=8) (actual time=856.423..856.424 rows=1 loops=1)
  ->  Seq Scan on lfs_objects  (cost=0.00..106415.50 rows=2832186 width=0) (actual time=0.012..672.181 rows=2852607 loops=1)
        Filter: (file_store = 1)
        Rows Removed by Filter: 131
Planning time: 0.128 ms
Execution time: 856.470 ms
```

#### After & with `NULL`

```
Aggregate  (cost=68819.95..68819.96 rows=1 width=8) (actual time=583.355..583.355 rows=1 loops=1)
  ->  Index Only Scan using index_lfs_objects_on_file_store on lfs_objects  (cost=0.43..61688.35 rows=2852643 width=0) (actual time=0.028..399.177 rows=2852607 loops=1)
        Filter: ((file_store = 1) OR (file_store IS NULL))
        Rows Removed by Filter: 131
        Heap Fetches: 867
Planning time: 0.096 ms
Execution time: 583.404 ms
```

#### After, without `NULL`

```
Aggregate  (cost=68817.29..68817.30 rows=1 width=8) (actual time=490.550..490.551 rows=1 loops=1)
  ->  Index Only Scan using index_lfs_objects_on_file_store on lfs_objects  (cost=0.43..61685.68 rows=2852643 width=0) (actual time=0.040..311.760 rows=2852607 loops=1)
        Index Cond: (file_store = 1)
        Heap Fetches: 831
Planning time: 0.294 ms
Execution time: 490.590 ms
```

Closes https://gitlab.com/gitlab-org/gitlab-ee/issues/6067
2018-10-30 08:42:11 +01:00

43 lines
1.2 KiB
Ruby

# frozen_string_literal: true
class LfsObject < ActiveRecord::Base
include AfterCommitQueue
include ObjectStorage::BackgroundMove
has_many :lfs_objects_projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :projects, through: :lfs_objects_projects
scope :with_files_stored_locally, -> { where(file_store: LfsObjectUploader::Store::LOCAL) }
validates :oid, presence: true, uniqueness: true
mount_uploader :file, LfsObjectUploader
after_save :update_file_store, if: :file_changed?
def update_file_store
# The file.object_store is set during `uploader.store!`
# which happens after object is inserted/updated
self.update_column(:file_store, file.object_store)
end
def project_allowed_access?(project)
projects.exists?(project.lfs_storage_project.id)
end
def local_store?
file_store == LfsObjectUploader::Store::LOCAL
end
# rubocop: disable DestroyAll
def self.destroy_unreferenced
joins("LEFT JOIN lfs_objects_projects ON lfs_objects_projects.lfs_object_id = #{table_name}.id")
.where(lfs_objects_projects: { id: nil })
.destroy_all
end
# rubocop: enable DestroyAll
def self.calculate_oid(path)
Digest::SHA256.file(path).hexdigest
end
end