如何从速度的角度改进以下功能?理想情况下,我希望将executemany用作此过程的一部分。
虽然功能正常,但我确信有更有效的方法可以做到这一点;检查是否存在值并根据情况更新/插入。
我需要每天在数百万个数据中执行此操作。
float int
答案 0 :(得分:4)
如果您需要这样做数百万次,那么这里存在许多性能问题。
你一遍又一遍地准备相同的SQL语句,数百万次。准备一次并执行数百万次会更好。
在单个查询后,您在每次函数调用时都与数据库断开连接。这意味着您需要每次重新连接,并丢弃任何缓存的信息。不要这样做,保持联系。
你在每一行之后做出承诺。这会减慢速度。相反,在完成批处理后提交。
select + update或insert可以作为单个upsert完成。
您将这么多插入临时表可能是一个性能问题。
如果表中有太多索引可能会降低插入速度。有时最好删除索引,进行大批量更新,然后重新创建它们。
由于您将值直接放入SQL,因此您的SQL向SQL injection attack开放。
,而不是...
UPDATE
而不是SELECT + math + UPDATE
。SELECT
,而是UPDATE
或INSERT
首先,准备好的陈述。这些让MySQL编译语句一次然后重用它。我们的想法是你用值的占位符写一个声明。
select id, position, impressions, clicks, ctr
from temp
where profile_id=%s and
keyword=%s and
landing_page=%s
然后使用值作为参数执行它,而不是作为字符串的一部分。
self.cursor.execute(
'select id, position, impressions, clicks, ctr from temp where profile_id=%s and keyword=%s and landing_page=%s',
(profile_id, keyword, landing_page)
)
这允许数据库缓存预准备的语句,而不必每次都重新编译它。它还避免了SQL注入攻击,聪明的攻击者可以创建一个实际上更像SQL " MORE SQL HERE "
的SQL。这是一个非常非常常见的安全漏洞。
注意,您可能需要使用MySQL's own Python database library to get true prepared statements。不要太担心,使用准备好的陈述不是你最大的性能问题。
接下来,您基本上做的是添加到现有行,或者如果没有现有行,则插入新行。这可以通过UPSERT
,合并INSERT
和UPDATE
的单个语句更有效地完成。 MySQL has it as INSERT ... ON DUPLICATE KEY UPDATE
要了解这是如何完成的,我们可以将您的SELECT then UPDATE
写为一个UPDATE
。计算在SQL中完成。
update temp
set impressions = impressions + %s,
clicks = clicks + %s,
ctr = (ctr + %s / 2)
where profile_id=%s and
keyword=%s and
landing_page=%s
你的INSERT保持不变......
insert into temp
(profile_id, landing_page, keyword, position, impressions, clicks, ctr)
values (%s, %s, %s, %s, %s, %s, %s)
将它们组合成一个INSERT ON DUPLICATE KEY UPDATE。
insert into temp
(profile_id, landing_page, keyword, position, impressions, clicks, ctr)
values (%s, %s, %s, %s, %s, %s, %s)
on duplicate key update
update temp
set impressions = impressions + %s,
clicks = clicks + %s,
ctr = (ctr + %s / 2)
这取决于表的键定义为什么。如果您有unique( profile_id, landing_page, keyword )
,那么它应该与您的代码相同。
即使你不能进行upsert,你也可以通过尝试SELECT
来消除UPDATE
,检查它是否有任何更新,以及它是否做了{ {1}}。
批量处理更新。不是调用一个更新和提交的子例程,而是传递一大堆要更新的内容并在循环中处理它们。您甚至可以利用executemany
运行具有多个值的相同语句。然后提交。
您可以批量执行INSERT
。 UPSERT
可以一次占用多行。例如,这会插入三行。
INSERT
您可以对insert into whatever
(foo, bar, baz)
values (1, 2, 3),
(4, 5, 6),
(7, 8, 9)
执行相同操作,从而减少与数据库通信的开销。请参阅this post for an example(在PHP中,但您应该能够适应)。
这会牺牲返回最后一个插入行的ID,但它们是中断。