使用巨大的 where 子句优化 SQL 查询
Optimising a SQL query with a huge where clause
我正在开发一个系统(Laravel),用户可以在其中填写一些过滤器来获取他们需要的数据。
数据不是实时准备的,一旦设置了过滤器,一个作业就会被推送到队列中,一旦查询完成就会创建一个 CSV 文件。然后用户会收到一封电子邮件,其中包含已创建的文件,以便他们可以下载。
我发现作业中存在一些错误,处理一项作业的时间超过 30 分钟,当我检查时,我发现一些用户创建了包含超过 600 个值的过滤器。
此过滤器值翻译如下:
SELECT filed1,
field2,
field6
FROM table
INNER JOIN table2
ON table.id = table2.cid
/* this is how we try not to give same data to the users again so we used NOT IN */
WHERE table.id NOT IN(SELECT data_id
FROM data_access
WHERE data_user = 26)
AND ( /* this bit is auto populated with the filter values */
table2.filed_a = 'text a'
OR table2.filed_a = 'text b'
OR table2.filed_a = 'text c' )
好吧,我没想到用户会疯狂地使用庞大的过滤器集进行微调。他们这样做没问题,但需要一个解决方案来加快查询速度。
一种方法是使用过滤器值动态创建临时 table 并隐藏 INNER JOIN
的查询,但不确定它是否会提高性能。
此外,考虑到在正常情况下系统需要创建至少 40 个临时 tables 并在之后删除它们。这会成为长期 运行 中的另一个问题吗?
除了 temp table 方法之外,我很想听听任何其他可以帮助我解决此问题的建议。
我建议这样写查询:
SELECT ?.filed1, ?.field2, ?.field6 -- qualify column names (but no effect on performance)
FROM table t JOIN
table2 t2
ON t.id = t2.cid
WHERE NOT EXISTS (SELECT 1
FROM data_access da
WHERE t.id = da.data_id AND da.data_user = 26
) AND
t2.filed_a IN ('text a', 'text b', 'text c') ;
那我推荐索引。最有可能:
table2(filed_a, cid)
table1(id)
(如果 id
已经是主键,则可能不需要)
data_access(data_id, data_user)
您可以将其作为您自己的查询进行测试。我不知道如何让 Laravel 产生这个(假设它符合您的性能目标)。
我正在开发一个系统(Laravel),用户可以在其中填写一些过滤器来获取他们需要的数据。 数据不是实时准备的,一旦设置了过滤器,一个作业就会被推送到队列中,一旦查询完成就会创建一个 CSV 文件。然后用户会收到一封电子邮件,其中包含已创建的文件,以便他们可以下载。
我发现作业中存在一些错误,处理一项作业的时间超过 30 分钟,当我检查时,我发现一些用户创建了包含超过 600 个值的过滤器。
此过滤器值翻译如下:
SELECT filed1,
field2,
field6
FROM table
INNER JOIN table2
ON table.id = table2.cid
/* this is how we try not to give same data to the users again so we used NOT IN */
WHERE table.id NOT IN(SELECT data_id
FROM data_access
WHERE data_user = 26)
AND ( /* this bit is auto populated with the filter values */
table2.filed_a = 'text a'
OR table2.filed_a = 'text b'
OR table2.filed_a = 'text c' )
好吧,我没想到用户会疯狂地使用庞大的过滤器集进行微调。他们这样做没问题,但需要一个解决方案来加快查询速度。
一种方法是使用过滤器值动态创建临时 table 并隐藏 INNER JOIN
的查询,但不确定它是否会提高性能。
此外,考虑到在正常情况下系统需要创建至少 40 个临时 tables 并在之后删除它们。这会成为长期 运行 中的另一个问题吗?
除了 temp table 方法之外,我很想听听任何其他可以帮助我解决此问题的建议。
我建议这样写查询:
SELECT ?.filed1, ?.field2, ?.field6 -- qualify column names (but no effect on performance)
FROM table t JOIN
table2 t2
ON t.id = t2.cid
WHERE NOT EXISTS (SELECT 1
FROM data_access da
WHERE t.id = da.data_id AND da.data_user = 26
) AND
t2.filed_a IN ('text a', 'text b', 'text c') ;
那我推荐索引。最有可能:
table2(filed_a, cid)
table1(id)
(如果id
已经是主键,则可能不需要)data_access(data_id, data_user)
您可以将其作为您自己的查询进行测试。我不知道如何让 Laravel 产生这个(假设它符合您的性能目标)。