选择包含所有指示值的ID(通配符冲突问题)MariaDB

时间:2019-09-01 14:39:24

标签: mysql sql group-by mariadb sql-like

有问题的表格(10.1.29-MariaDB):

  [Table] => blog_search
  [Create Table] => CREATE TABLE `blog_search` (
  `bkey` varchar(28) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
  `blog_id` int(10) unsigned NOT NULL,
  `follows` int(10) unsigned NOT NULL,
  UNIQUE KEY `bkey` (`bkey`,`blog_id`),
  UNIQUE KEY `blog_id` (`blog_id`,`bkey`) USING BTREE,
  KEY `bkey_follows` (`bkey`,`follows`,`blog_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

bkey是博客标题中使用的单词。 follows数据将在每个博客的每个单词中重复。

我有一个Select,它在没有通配符(数据库选择key => bkey_follow)的情况下效果很好:

SELECT blog_id
FROM blog_search
WHERE bkey = 'news' OR bkey = 'usa'
GROUP BY blog_id
HAVING COUNT(*) > 1
ORDER BY FOLLOWS DESC
LIMIT 30

但是当我使用通配符(DB选择的key => bkey)时:

WHERE bkey LIKE 'news%' OR bkey LIKE 'usa%'

它仍然可以进行索引搜索,但是' news '和' newsletter '关键字将匹配为COUNT(*)= 2,但是它将找不到“ 美国

我做了这个新查询,其工作原理与我想要的一样,但是如果最后一个单词有很多结果,则查询会变慢得多(因为查询是从头到尾执行的,必须读取100%的索引) (密钥=> blog_id由数据库选择):

SELECT blog_id
FROM blog_search
WHERE  
  blog_id IN (SELECT blog_id FROM blog_search WHERE bkey LIKE 'news%') 
  AND blog_id IN (SELECT blog_id FROM blog_search WHERE bkey LIKE 'usa%')
GROUP BY blog_id
ORDER BY follows DESC
LIMIT 30

如果我FORCE INDEX (bkey)甚至更好的FORCE INDEX (bkey_follows),它会有所改善,例如35%,但仍然比我认为应该慢10倍。

我想要一个更优化的查询,没有子查询。这样的 WRONG 查询,(但版本正确)

SELECT blog_id, 0 AS dist1, 0 AS dist2
FROM blog_search
WHERE ( bkey LIKE 'news%' AND 1=dist1=1 )
   OR ( bkey LIKE 'usa%' AND 1=dist2=1 )
GROUP BY blog_id
HAVING (dist1=1 AND dist2=1)
ORDER BY follows DESC
LIMIT 30

其他数据:我正在搜索博客/帖子的标题。我尝试了很多事情:正则表达式,LIKE%...%和FULLTEXT索引,我“批准”它们用于相关性排序结果。最有希望的搜索是此问题中讨论的搜索,因为这对于它的速度和按“跟随”排序结果是最好的。

2 个答案:

答案 0 :(得分:1)

您可以将having子句表达为:

SELECT blog_id
FROM blog_search
WHERE bkey LIKE 'news%' OR bkey = 'usa%'
GROUP BY blog_id
HAVING SUM( bkey LIKE 'news%' ) > 0 AND
       SUM( bkey LIKE 'usa%' ) > 0
ORDER BY FOLLOWS DESC
LIMIT 30

在聚合之前进行过滤的一种便捷方法是使用正则表达式:

SELECT blog_id
FROM blog_search
WHERE bkey REGEXP 'news|use' 
GROUP BY blog_id
HAVING SUM( bkey LIKE 'news%' ) > 0 AND
       SUM( bkey LIKE 'usa%' ) > 0
ORDER BY FOLLOWS DESC
LIMIT 30

答案 1 :(得分:1)

您不在乎有多少行匹配。许多其他解决方案导致“爆炸爆炸”综合症。那是您收集大量行的地方,然后通过GROUP BY简化为几行。通过使用“半连接” EXISTS可以避免一半的情况。

SELECT DISTINCT blog_id
    FROM blog_search AS o
    WHERE WHERE bkey LIKE 'news%'
      AND EXISTS ( SELECT blog_id FROM blog_search
                      WHERE bkey LIKE 'usa%'
                        AND blog_id = o.blog_id )
ORDER BY follows DESC
LIMIT 30