Mysql 优化数据库查询,结果最多为10mil行

Mysql 优化数据库查询,结果最多为10mil行,mysql,sql,performance,solr,large-data,Mysql,Sql,Performance,Solr,Large Data,我有一个MySQL查询,我需要尽可能地优化它(如果可能的话,加载时间应该在5s以下) 查询如下: 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

我有一个MySQL查询,我需要尽可能地优化它(如果可能的话,加载时间应该在5s以下)

查询如下:

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是来自输入的整数
  • 域id和关键字id被索引
  • 数据库位于本地主机上,因此网络速度应为最大

WHERE子句的子查询最多可以得到10 mil的结果。另外,对于MySQL,似乎很难通过这个计数来计算计数和顺序

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

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

谢谢


查询逻辑如下:

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


我希望这有意义

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

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 ...

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

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 ...

我不是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
子句替换为
内部连接
,这将使它变得更快
WHERE-IN
子句总是让Mysql服务器陷入困境,但在处理大量数据时,这一点更为明显。使用
WHERE IN
仅当它使您的查询看起来更易于阅读/理解,您的数据集较小,或者无法以其他方式进行查询(但您可能会有其他方式进行:)

我不是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
子句替换为
内部连接
,这将使它变得更快
WHERE-IN
子句总是让Mysql服务器陷入困境,但在处理大量数据时,这一点更为明显。使用
WHERE IN
仅当它使您的查询看起来更易于阅读/理解,您的数据集较小,或者无法以其他方式进行查询时(但您可能会有其他方式进行查询:))

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

由于
keyword\u id
在表的另一个副本中有匹配项,
COUNT(keyword\u id)
变为
COUNT(*)

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

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

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
SELECT DISTINCT keyword_id FROM tableName WHERE domain_id = X
如果使用覆盖复合索引
(关键字_id,域_id[,…])
,将具有最佳性能,因此它是必须的。从另一方面来看,查询类似于:

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
SELECT DISTINCT keyword_id FROM tableName WHERE domain_id = X
将在覆盖复合索引上具有最佳性能
(域id、关键字id[,…])
。所以你们两个都需要

希望如此,但我不确定,当您使用后一个索引时,MySQL可以理解您不需要在子查询中选择所有这些
关键字\u 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
您再次需要这两个复合索引


哪一个查询更快取决于MySQL中
tableName

的统计信息。您所能做的就是使用覆盖索引最小化查询的磁盘IO,并将其重写得更高效一些,以便查询从中受益

由于
keyword\u id
在表的另一个副本中有匹配项,
COUNT(keyword\u id)
变为
COUNT(*)

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

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

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
SELECT DISTINCT keyword_id FROM tableName WHERE domain_id = X
如果使用覆盖复合索引
(关键字_id,域_id[,…])
,将具有最佳性能,因此它是必须的。从另一方面来看,查询类似于:

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
SELECT DISTINCT keyword_id FROM tableName WHERE domain_id = X
将在覆盖复合索引上具有最佳性能
(域id、关键字id[,…])
。所以你们两个都需要

希望如此,但我不确定,当您使用后一个索引时,MySQL可以理解您不需要在子查询中选择所有这些
关键字\u 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

中的统计信息。为什么需要内部查询?您可以在where子句中使用domain\u id=x?如果没有,则在域_id上添加索引present@shola请仔细查看查询,它是关于相关数据的。您可以发布解释吗?“WHERE子句的子查询最多可以得到10 mil个结果。”-您有10 mil个不同的关键字@Vatev还有很多,但这不是重点…为什么需要内部查询,您可以在where子句中使用domain_id=x?如果没有,则在域_id上添加索引present@shola请仔细看这个查询,它是关于相关数据的