SQL inner join 的性能可以提高吗?

Can the performance of this SQL inner join be improved?

我正在使用 python 和 sqllite3,我想知道是否可以提高此查询的性能?

main table 约 100,000 行


    0   1   2   3   4   Amount
0   0   9   12  6   60  40800.0
1   0   9   12  6   61  40100.0
2   0   9   12  6   65  39900.0
3   0   9   12  6   74  40300.0
4   0   9   12  7   60  40600.0

util table ~75,000 行


    0   1   2   Amount
0   78  75  65  9900.0
1   80  75  65  9900.0
2   80  72  65  10000.0
3   78  72  65  10000.0
4   79  75  65  10000.0

查询当前获取的是两个table的笛卡尔积,其中金额之和在49,700和50,000之间,如果我的理解正确,则获取前200,000个匹配项。

con = sqlite3.connect(':memory:')
df.to_sql(name='main', con=con)
df1.to_sql(name='util', con=con)

query = '''
SELECT *
FROM main AS m
INNER JOIN
util AS u
ON
  50000 >= m.Amount + u.Amount
AND
  49700 <= m.Amount + u.Amount
LIMIT
  200000;
'''
final_df = pd.read_sql_query(query, con)

由于您不是在列值上进行匹配,而是在表达式m.Amount + u.Amount上进行匹配,因此必须计算每个可能的组合两个 table 之间的行数 (100k * 75k = 75 亿或 75 亿个组合)。您实际上得到的是 CROSS JOIN,因为您在两个 table 之间的任何列上都不匹配。

1. 通过使用BETWEEN 运算符。为了清楚起见,我只使用标准 'from table1, table2' 和 WHERE

SELECT * FROM main AS m
INNER JOIN
util AS u
ON
  m.Amount + u.Amount BETWEEN 49700 AND 50000
;

2. 您必须使用其他方法来减少检查的行数。例如,当任何一个 table 的 Amount 超过 50,000 时,它就不能匹配,因此它在验证中较早地被排除,并且通过不计算 m.Amount + u.Amount 甚至一次来节省时间:

SELECT * FROM main AS m, util AS u
WHERE
  m.Amount <= 50000
AND
  u.Amount <= 50000
AND
  m.Amount + u.Amount BETWEEN 49700 AND 50000
;

如果金额不能为0,则将<= 50000改为< 50000

3. 你可以做其他事情,比如在每个 table 中找到最小金额,然后确保另一个 table 的金额是小于 50000 - that first min amt.

4. 使用“2 个数之和”问题,您可以 one-time 计算最小匹配金额和最大匹配金额(添加两个新的列)用于 table 之一,然后使用来自另一个 table 的 Amt 进行 BETWEEN 检查。它仍然需要进行交叉连接,但减少了评估每个匹配项的 cpu-time。

ALTER TABLE main ADD COLUMN min_match INT default 0;
ALTER TABLE main ADD COLUMN max_match INT default 0;
UPDATE main SET min_match = 49700 - Amount,
                max_match = 50000 - Amount;

SELECT * FROM main AS m, util AS u
WHERE
  u.Amount BETWEEN m.min_match AND m.max_match
;