【问题标题】:Optimal search query and structure for querying large set of data用于查询大量数据的最佳搜索查询和结构
【发布时间】:2016-03-19 18:58:59
【问题描述】:

我创建了文件索引器,它只是将文件名插入到指定的表中。现在我正在考虑搜索文件名的最佳方式。表中可能有 100000 多个文件,因此性能很重要。

文件名可以是不同的 - 长度为 10、20、50 或更多字符。至少目前,我的测试数据集没有名称中包含空格的文件。用户可以进行部分搜索,例如查找“1001”应返回名称为 10_1001_20_30_40_50 的文件。

我当前的表结构:

CREATE TABLE `file` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `id_category` int(10) unsigned NOT NULL,
  `filename` varchar(255) NOT NULL,
  `file_ext` varchar(3) NOT NULL,
  `date_added` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`,`id_category`),
  KEY `idx_file_filename` (`filename`) USING BTREE,
  KEY `fk_file_1_idx` (`id_category`),
  FULLTEXT KEY `filename` (`filename`)
) ENGINE=MyISAM AUTO_INCREMENT=24974 DEFAULT CHARSET=utf8;

INSERT INTO `file` (`id`,`id_category`,`filename`,`file_ext`,`date_added`) VALUES (22474,14199,'095_98_1002_1003_148_98_1001_003','pdf','2016-03-19 19:02:12');
INSERT INTO `file` (`id`,`id_category`,`filename`,`file_ext`,`date_added`) VALUES (22475,14199,'095_98_1002_1003_148_98_1001_001','pdf','2016-03-19 19:02:11');

我尝试过使用 MATCH () AGAINST (),但结果表明,如果字符串中没有空格并且想要执行“如果字符串包含搜索”这样的操作,这不是一个好主意:

SELECT id, filename FROM `file` WHERE MATCH(filename) AGAINST ('1002*' IN BOOLEAN MODE);

这不会返回我需要的东西。我正在考虑的是通过拆分所有文件名来使用 FULLTEXT,同时导入由空格分隔的 3 个长度(用户可以提供的最小字符串长度)部分,它们使用如下查询:

SELECT * FROM `file` WHERE MATCH(filename) AGAINST ('100*' IN BOOLEAN MODE);

当然,我可以保留文件名并使用 LIKE 运算符:

SELECT * FROM `file` WHERE filename LIKE '%100%'

但是对于大型数据集使用 LIKE 有很多负面意见。我很好奇我在文件名中添加空格的解决方案是否是个好主意。

【问题讨论】:

  • Ale 您只寻找 1002,还是您也想搜索更长的序列 (1002_1003)?
  • 可以是任何查询 >= 3 个字符

标签: mysql performance full-text-search sql-like


【解决方案1】:

尝试使用 FULLTEXT:需要空间,限制您(大部分)使用完整的“单词”,使用“短”单词效率低下,错过“停用词”等。

LIKE '%100%',虽然效率低,因为它必须测试每一行,但这正是您所需要的。

您暗示文件名的所有相关部分都是数字?并且您只想测试整个零件?即22_100_33 将搜索2210033,但不会搜索21000 等??如果是这样,那么LIKE 将无法正常工作。示例:101_1000 将被LIKE '%100%'捕获。

所以,也许您想建立一个“倒排索引”:对于10_1001_20_30_40_50,您将在一个表中有 6 行:101001 等,或者其余列,或一些用于加入 file 表的 id。

【讨论】:

  • 感谢您与 FT 结清案件。我会测试零件,我需要零件回来,所以 LIKE 是可以的。文件名和其中的部分可以是字母数字,各种长度,所以我不能使用你提出的倒排索引结构。问题仍未解决 - 现在看来我必须使用 LIKE。
【解决方案2】:

对于大型数据集使用 LIKE 有很多负面意见

可能对你的情况来说已经足够好了,我会先测试一下。

如果您真的想加快速度,我可以考虑一种选择,但牺牲将是巨大的 - 内存、插入时间、可维护性、灵活性、复杂性......您可以为后缀构建“倒排索引”。该表看起来像(伪代码):

CREATE TABLE Pref(
    prefix varchar(255) NOT NULL,
    fileid bigint(20) unsigned NOT NULL,

CONSTRAINT [PK_Pref] PRIMARY KEY CLUSTERED 
(
    prefix ASC,
    fileid ASC
)) 

并且有这样的数据

'095_98_1002_1003_148_98_1001_003', 22474
'95_98_1002_1003_148_98_1001_003', 22474
'5_98_1002_1003_148_98_1001_003', 22474
'_98_1002_1003_148_98_1001_003', 22474
'98_1002_1003_148_98_1001_003', 22474
...
'03', 22474
'3', 22474

它会在两列上都聚集主键。这样它将按前缀排序,您可以将中缀搜索'%abcd%' 更改为前缀搜索'abcd%'。查询将具有以下形式

SELECT id, filename FROM `file` 
WHERE id IN (SELECT fileid FROM Pref WHERE prefix like 'abcd%')

您只需创建触发器以使其与主表保持同步。请注意,当您删除此表中的行时,应避免搜索未指定前缀的 fileid,否则性能将是灾难。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-31
    • 1970-01-01
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多