Hi
I would like to share my experience in keeping oc_filecache table under control and perhaps offer some food for thought on the matter.
The database of our NC instance periodically fills up the storage space allocated to it.
The reason is always the same:
users configure an external storage (SMB in our case) that contains millions of files that get recursively indexed.
Today oc_filecache table is ~500GB.
nextcloud> explain select count(*) from oc_filecache;
+------+-------------+--------------+-------+---------------+----------+---------+------+-----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |`
+------+-------------+--------------+-------+---------------+----------+---------+------+-----------+-------------+
| 1 | SIMPLE | oc_filecache | index | NULL | fs_mtime | 8 | NULL | 597421495 | Using index |
+------+-------------+--------------+-------+---------------+----------+---------+------+-----------+-------------+
597421495 rows !
So I proceed as follows:
- find which ID storage is bloating oc_filecache table using a stored procedure (see below):
nextcloud> CALL count_per_storage();
+---------------------------------------------------------------+------------+-----------+
| storage | numeric_id | cnt |
+---------------------------------------------------------------+------------+-----------+
[...]
| smb::user0@mynas//goodpath// | 5765 | 9013645 |
| smb::user1@mynas//evilpath// | 8719 | 158185971 |
| smb::user2@mynas//evilpath// | 8734 | 158200126 |
| smb::user3@mynas//evilpath// | 8840 | 159041494 |
(after first call you can do: SELECT * FROM storage_count ORDER BY cnt;
- add “evilpath” to excluded dirs list
occ config:app:get files_excludedirs exclude
occ config:app:set files_excludedirs exclude --value '[".snapshot",.......,"evilpath"]'
- since deleting hundreds of millions of records from oc_filecache would take days/weeks,
I leverage percona-toolkit and by mimicking an alter table I exclude unnecessary records
(see numeric_id above example) from the copy:
pt-online-schema-change --alter "ENGINE=InnoDB" --where "storage NOT IN (8719,8734,8840)" --user=mysqluser --password=mysqlpassword --host localhost D=nextcloud,t=oc_filecache --execute
(I have deliberately omitted the--forceoption in case someone copies&pastes without understanding the potential danger of this command)
#####################################
#with a little help of my frAInd
#this procedure create a ‘storage_count’ table listing all storages with more than 100K files
CREATE PROCEDURE `count_per_storage`()
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE sid BIGINT;
DECLARE sname VARCHAR(255);
DECLARE cnt BIGINT;
DECLARE cur CURSOR FOR SELECT numeric_id, id FROM oc_storages;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DROP TABLE IF EXISTS storage_count;
CREATE TABLE storage_count (
storage VARCHAR(255),
numeric_id BIGINT,
cnt BIGINT
);
OPEN cur;
loop_label: LOOP
FETCH cur INTO sid, sname;
IF done THEN LEAVE loop_label; END IF;
SELECT COUNT(*) INTO cnt FROM oc_filecache WHERE storage = sid;
IF cnt > 100000 THEN
INSERT INTO storage_count VALUES (sname, sid, cnt);
END IF;
END LOOP;
CLOSE cur;
SELECT * FROM storage_count ORDER BY cnt DESC;
END