有问题的表格(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索引,我“批准”它们用于相关性排序结果。最有希望的搜索是此问题中讨论的搜索,因为这对于它的速度和按“跟随”排序结果是最好的。
答案 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