我有一个 INSERT
查询从何处获取值 SELECT
声明。但是自从 SELECT
返回数百万条记录,这给mysql服务器带来了太多的负载。所以,我们决定打破僵局 SELECT
查询成部分并通过 LIMIT
条款。
INSERT INTO target_table
SELECT * FROM source_table
WHERE my_condition = value
...
LIMIT <start>, <end>
我们将继续增加起始值和结束值,直到 SELECT
退货 0
排。我也在考虑做这个多线程的。
如何使用pymysql?
我需要执行 SELECT
,获取结果,然后生成 INSERT
?
1条答案
按热度按时间30byixjq1#
首先,回答您的问题:在pymysql中,您得到的值是
cursor.execute
:因此,您可以重复执行查询,直到得到的值小于所选范围。
无论如何,请考虑:
第一件事你应该检查你是否可以优化你的
select
(假设它不像您的示例中那么简单),例如,通过添加索引。您可能还需要测试选择和实际插入之间的区别,以大致了解哪个部分更相关。如果插入导致了问题,则可能是由于事务的大小。在这种情况下,如果您还可以拆分事务,那么拆分事务只会减少问题(尽管由于您考虑并行执行查询,所以这似乎不是一个问题)
如果一个查询产生过多的(cpu)负载,那么并行运行该查询的多个示例最多只能将其分布在多个内核上,这实际上会减少其他查询的可用cpu时间。如果“负载”与i/o负载、有限资源的影响或“一般响应性”有关,那么也有可能,例如,一个小查询可能会在内存中生成一个小临时表,而大查询则会在磁盘上生成一个大临时表(尽管特别是
offset
否则,通常需要在连续运行的部分(足够小)之间添加小的暂停,以便在更长的时间内分散相同的工作负载。limit
只有当你有一个order by
(可能通过主键),否则,在连续运行中m
-第行可以是与之前不同的行(因为顺序不固定)。这可能会也可能不会增加负载(和资源需求),这取决于您的索引和where
-条件。对源表的更新也是如此,就像从结果集中添加或删除一行一样(例如,更改
my_condition
对于第一行),所有连续的偏移量都将移动,您可以跳过一行或获取一行两次。您可能需要锁定行,这可能会阻止并行运行查询(因为它们锁定相同的行),并且如果您可以拆分事务,也可能会影响决策(请参阅第二个要点)。使用
offset
需要mysql先查找行,然后跳过行。所以如果你把查询分成n
零件,第一行需要加工n
次(最后一行通常为一次),因此总工时(用于选择)将增加(n^2-n)/2
. 因此,特别是如果选择行是最相关的部分(请参阅第一个要点),这实际上会使情况更糟:仅最后一次运行就需要找到与当前查询相同数量的行(尽管它会丢弃大部分行),甚至可能需要更多的资源,这取决于查询的效果order by
.你也许可以绕过一些
offset
-在条件中使用主键的问题,例如,有一个包含以下内容的循环:退出循环如果
new_max
是null
,否则插入:然后设置
last_id = new_max
继续循环。它将查询的数量增加了一倍,这与
limit
带着一个offset
,你需要知道id
. 它仍然需要您的主键和where
-条件是兼容的(因此您可能需要添加一个适合的索引)。如果您的搜索条件在源表中发现了很大一部分(超过15%或20%),那么使用主键可能是最好的执行计划。如果您想将其并行化(取决于您的事务需求,如果它可能有价值,请参见上文),您可以首先获得主键的最大值(
select max(id) as max_id from ...
),并为每个线程提供一个可处理的范围。e、 g.用于max_id=3000
三个线程,从其中一个开始(0..1000), (1001, 2000), (2001..3000)
并将其包含在第一个查询中:如果这些范围大小相等,则可能取决于您的数据分布(您可能会在您的情况下找到更好的范围;但是,计算准确的范围需要执行查询,因此您可能无法做到准确)。