Skip to content

Use FTS for contact search instead of LIKE #18965

@fladi

Description

@fladi

We are experiencing long delays when selecting contacts to create new shares for. Searching takes about 20-30 seconds after the user has finished typing.

Our installation runs Nextcloud 16 with PHP 7.3 and MariaDB 10.3. We have 22k rows in oc_cards and 140k rows in oc_cards_properties.

Testing the queries created by OCA\DAV\CardDAV\CardDavBackend->search manually showed that each one takes about 4 seconds to complete, like this one:

SELECT `c`.`carddata`, `c`.`uri` FROM `oc_cards` `c` WHERE `c`.`id` IN (SELECT DISTINCT `cp`.`cardid` FROM `oc_cards_properties` `cp` WHERE (`cp`.`addressbookid` = 'XXX') AND ((`cp`.`name` = 'EMAIL') OR (`cp`.`name` = 'FN')) AND (`cp`.`value`  COLLATE utf8mb4_general_ci LIKE '%pattern%'));

As LIKE statements can only make use of indizes if they do not start with a % wildcard, each query has to to a full table scan.
I tried to compare this with a FTS index on the oc_cards_properties.value field and using MATCH ... AGAINST ... instead of LIKE:

CREATE FULLTEXT INDEX oc_cards_properties_name_FTS ON nextcloud.oc_cards_properties (value);
SELECT `c`.`carddata`, `c`.`uri` FROM `oc_cards` `c` WHERE `c`.`id` IN (SELECT DISTINCT `cp`.`cardid` FROM `oc_cards_properties` `cp` WHERE (`cp`.`addressbookid` = 'XXX') AND ((`cp`.`name` = 'EMAIL') OR (`cp`.`name` = 'FN')) AND (MATCH(`cp`.`value`) AGAINST('pattern')));

Now the query took only ~220ms instead of 4000ms.

Would you consider switching to Full-Text-Search, at least for MySQL/MariaDB? Large installations like ours would certainly benefit from it. Doctrine support for MATCH is available in https://github.com/beberlei/DoctrineExtensions.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions