将WHERE与COALESCE一起使用非常慢

时间:2019-03-26 21:00:47

标签: mysql sql

我有以下查询,大约需要一分钟才能运行:

SELECT * FROM main_i i JOIN main_p p ON p.item_id=i.id
WHERE COALESCE(p.provider_title_id, i.provider_title_id) = "X"

虽然这看起来很简单,但要花很长时间才能运行,而我能够解决的唯一方法是使用以下方法:

SELECT * FROM main_i i JOIN main_p p ON p.item_id=i.id
WHERE p.provider_title_id = "X"
UNION
SELECT * FROM main_i i JOIN main_p p ON p.item_id=i.id
WHERE i.provider_title_id = "X" AND p.provider_title_id IS NULL

这瞬间完成,但是查询看起来如此愚蠢,以至于必须有更好的方法来执行此操作。

我在这里应该使用什么?

3 个答案:

答案 0 :(得分:1)

在您的第一个查询中,谓词import pandas as pd lines = [] # Declare an empty list named "lines" with open ('03-22-2019.txt', 'rt') as in_file: # Open file for line in in_file: # For each line of text in in_file, where the data is named "line", lines.append(line.rstrip('\n')) # add that line to our list of lines, stripping newlines. while('' in lines): lines.remove("") lines = [x for x in lines if 'A123' not in x] #delete all lines with 'A123' for element in lines: # For each element in our list, print(element) # print it. split_line = lines[0].split() # create list with serial number line Serial_Num = split_line[-1] print(Serial_Num) split_line = lines[1].split() # go to line with CMS SN CMS_SN = split_line[-1] print(CMS_SN) split_line = lines[2].split() Firm_Rev_1 = split_line[-1] Firm_Rev_2 = split_line[-2] print(Firm_Rev_1) print(Firm_Rev_2) # Problem section starts here! start_data = lines.index("log =") + 1 #<<<<<<<<<< data = [x for x in lines[start_data:].split(",")] #<<<<<<<<<< #dfObj = pd.DataFrame(lines[start_data:-1].split(",")) #<<<<<<<<<< 基于两个表中的列。这迫使MySQL使用此谓词作为“过滤谓词”,而不是“访问谓词”。

这在英语中是什么意思?这意味着MySQL使用[希望很快]访问谓词执行由COALESCE(p.provider_title_id, i.provider_title_id) = "X"产生的叉积,但是随后它被迫使用上述条件过滤整个结果集。叉积可能导致大量行将被该条件丢弃。进行大量工作,但成效不大。

第二个查询使用MySQL能够用来访问行的简单谓词。这次仅访问了几行。谓词对它们进行过滤,但是工作量非常有限。

如果您生成并比较每个查询的执行计划,您会发现这一点更加清晰。

答案 1 :(得分:1)

以我的经验,使用函数(例如COALESCE)可停止db引擎以预先优化行选择。数据库引擎无法确定最终结果,除非它们运行通过此类功能联接表而产生的每条记录。相反,对于第二个查询,db引擎完全知道在创建初始集时(在应用位置之前)要过滤的内容。您也许可以在查询说明计划中选择它。

如您所知,接下来是实现相同结果的另一种方法。这应该可以证明事实的速度更快。

SELECT *
FROM main_i i JOIN
     main_p p
     ON p.item_id = i.id
WHERE p.provider_title_id = 'X'
OR
(p.provider_title_id IS NULL 
AND i.provider_title_id = 'X')

答案 2 :(得分:0)

这很好,但是您应该使用UNION ALL

SELECT *
FROM main_i i JOIN
     main_p p
     ON p.item_id = i.id
WHERE p.provider_title_id = 'X'
UNION ALL
SELECT *
FROM main_i i JOIN
     main_p p 
     ON p.item_id = i.id
WHERE i.provider_title_id = 'X' AND p.provider_title_id IS NULL;

此版本允许优化器查看两个更简单的子查询。每个子查询可以利用一组不同的索引。通常,SQL在OR条件下处理不等式和JOIN时表现不佳。