1

我有一个 MySQL 查询,我需要尽可能优化(如果可能,加载时间应该低于 5 秒)

查询如下:

SELECT domain_id, COUNT(keyword_id) as total_count
FROM tableName
WHERE keyword_id IN (SELECT DISTINCT keyword_id FROM tableName WHERE domain_id = X)
GROUP BY domain_id
ORDER BY total_count DESC
LIMIT ...
  • X 是来自输入的整数
  • domain_id 和keyword_id 被索引
  • 数据库在本地主机上,所以网络速度应该是最大的

WHERE 子句的子查询最多可以获得 1000 万个结果。此外,对于 MySQL 来说,计算 COUNT 和 ORDER BY 这个计数似乎真的很困难。

我尝试将此查询与 SOLR 混合,但没有结果,一次获取如此多的行数给 MySQL 和 SOLR 带来了困难

我正在寻找一种具有相同结果的解决方案,无论我是否必须使用不同的技术或对此 MySQL 查询进行改进。

谢谢!


查询逻辑是这样的:

我们有一个域,我们正在搜索该域上使用的所有关键字(这是子查询)。然后我们取所有使用第一个查询中找到的至少一个关键字的域,按域分组,每个域使用的关键字数量,我们必须按使用的关键字数量排序 DESC。

我希望这是有道理的

4

3 回答 3

1

您可以尝试 JOIN 而不是子查询:

SELECT tableName.domain_id, COUNT(tableName.keyword_id) AS total_count
FROM tableName
INNER JOIN tableName AS rejoin
ON rejoin.keyword_id = tableName.keyword_id
WHERE rejoin.domain_id = X
GROUP BY tableName.domain_id
ORDER BY tableName.total_count DESC
LIMIT ...
于 2013-03-26T09:36:44.547 回答
0

就 MySQL 而言,您所能做的就是使用覆盖索引最小化查询的磁盘 IO,并更高效地重写它,以便查询可以从中受益。

由于keyword_id在表的另一个副本中有匹配项,因此COUNT(keyword_id)变为COUNT(*).

众所周知,您使用的子查询类型对于 MySQL 来说是最坏的情况(它为每一行执行子查询),但我不确定它是否应该在JOIN这里替换为 a,因为它可能是您的数据的正确策略。

正如您可能理解的那样,查询如下:

SELECT domain_id, COUNT(*) as total_count
FROM tableName
WHERE keyword_id IN (X,Y,Z)
GROUP BY domain_id
ORDER BY total_count DESC

使用覆盖复合索引将具有最佳性能(keyword_id, domain_id [,...]),因此它是必须的。另一方面,查询如下:

SELECT DISTINCT keyword_id FROM tableName WHERE domain_id = X

将在覆盖综合指数上表现最佳(domain_id, keyword_id [,...])。所以你需要他们两个。

希望,但我不确定,当你有后一个索引时,MySQL 可以理解你不需要选择keyword_id子查询中的所有那些,但你只需要检查索引中是否有条目,我确信如果您不使用 DISTINCT,它会更好地表达。

所以,我会尝试添加这两个索引并将查询重写为:

SELECT domain_id, COUNT(*) as total_count
FROM tableName
WHERE keyword_id IN (SELECT keyword_id FROM tableName WHERE domain_id = X)
GROUP BY domain_id
ORDER BY total_count DESC

另一种选择是将查询重写如下:

SELECT domain_id, COUNT(*) as total_count
FROM (
  SELECT DISTINCT keyword_id
  FROM tableName
  WHERE domain_id = X
) as kw
JOIN tableName USING (keyword_id)
GROUP BY domain_id
ORDER BY total_count DESC

您再次需要这两个复合索引。

哪个查询更快取决于您的tableName.

于 2013-03-26T18:20:48.420 回答
0

我不是 100% 确定,但你能试试这个吗

SELECT t1.domain_id, COUNT(t1.keyword_id) as total_count
FROM tableName AS t1 LEFT JOIN
(SELECT DISTINCT keyword_id FROM tableName WHERE domain_id = X) AS t2
ON t1.keyword_id = t2.keyword_id
WHERE t2.keyword_id IS NTO NULL
GROUP BY t1.domain_id
ORDER BY total_count DESC
LIMIT ...

目标是将WHERE IN子句替换为INNER JOINand ,这将使其更快。WHERE IN子句总是让Mysql服务器陷入困境,但当您使用大量数据时,它会更加明显。仅当它使您的查询看起来更容易阅读/理解时使用WHERE IN,您有一个小数据集或以其他方式不可能(但无论如何您可能会有另一种方式来做到这一点:))

于 2013-03-26T09:38:33.530 回答