用于查询大量数据的最佳搜索查询和结构

时间:2016-03-19 18:59:00

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

我创建了文件索引器,它只是将文件名插入到指定的表中。现在我正在考虑搜索文件名的最佳方法。表中可能有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存在很多负面意见。我很好奇,如果我的解决方案为文件名添加空格将是一个好主意。

2 个答案:

答案 0 :(得分:0)

尝试使用FULLTEXT:需要空间,限制你(大部分)完全"单词",使用" short"单词,未命中和#34;停止单词"等。

if(true) { //to do } else { // to do } '虽然效率低,因为它必须测试每一行,但这正是您所需要的。

你暗示文件名的所有相关部分都是数字?而你只想测试整个零件?这将LIKE '%100%搜索22_100_3322100,但不会搜索33210等等?如果是这种情况,那么00将无法正常工作。示例:LIKE'。

将抓住101_1000

所以,也许你想建立一个倒排索引":对于LIKE '%100%,你会在表格中有6行:10_1001_20_30_40_5010等,以及其他列,或者一些用于加入1001表的id。

答案 1 :(得分:0)

  

对于使用LIKE进行大型数据集存在很多负面意见

对你的情况来说,这可能是好的,我会先测试它。

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

@IBAction func okButton(sender: UIButton) {
    resultOutputLabel.text == ""
}

并拥有此类数据

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%'

您只需制作触发器即可使其与主表保持同步。请注意,当您删除此表中的行时,您应该避免搜索没有指定前缀的fileid,否则性能将是一场灾难。