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
;
我正在使用 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
;