mysql以优化的方式将多列添加到大表中

时间:2017-10-27 08:12:56

标签: mysql database algorithm innodb in-place

我想在一个大的mysql(5.6版)表中添加8个新列,其中innodb有数百万条记录。我试图以最优化的方式实现这一目标。

  • 使用单个查询添加所有列而不是在8个不同查询中添加8列是否有任何优势。如果是这样想知道原因。

  • 指定 ALGORITHM = INPLACE,LOCK = NONE 时,我需要注意的一切是什么,以免造成任何数据损坏或应用程序失败!

我正在使用查询测试ALGORITHM = INPLACE,LOCK = NONE。

ALTER TABLE table_test ADD COLUMN test_column TINYINT UNSIGNED DEFAULT 0 ALGORITHM=INPLACE LOCK = NONE;

但它与ALGORITHM = DEFAULT运行查询的时间相同。可能是什么原因。

改变的表只有主键索引而没有其他索引。从应用程序到此表的查询是:

insert into table;
select * from table where user_id=uid;
select sum(column) from table where user_id=id and date<NOW();

1 个答案:

答案 0 :(得分:2)

通过&#34;优化&#34;,你的意思是&#34;最快&#34;?或者&#34;对其他查询的影响最小&#34;?

在旧版本中,最佳方式(不使用加载项)是将所有ADD COLUMNs放在一个ALTER TABLE中;然后等到它完成。

在任何版本中,pt-online-schema-change都会在短时间内添加所有列。

既然你提到ALGORITHM=INPLACE, LOCK=NONE,我假设你使用的是更新的版本?所以,可能是8 ALTERs是最优的。会有一些干扰,但可能不会太多&#34;。

ALGORITHM=DEFAULT让服务器选择最好的&#34;。这几乎总是最好的&#34;。也就是说,除了DEFAULT之外,很少需要说出任何其他内容。

您永远不会受到数据损坏。在最坏的情况下,由于ALTER(s)的干扰导致某种超时,查询可能会失败。您应该始终检查错误(包括超时),并在您的应用程序中处理它。

讨论查询...

insert into table;

一次一行?还是分批? (批量效率更高 - 可能提高10倍。)

select * from table;

当然不是!这将为您提供数百万行的所有列。你为什么要这样做?

select count(column) from table where pk=id and date<NOW();

COUNT(col)检查colNOT NULL - 您需要吗?如果没有,那么只需COUNT(*)

WHERE pk=id只给你一行;那么为什么还有资格date<NOW()PRIMARY KEY使查询尽可能快。

唯一的索引是PRIMARY KEY?对于百万行表来说,这似乎不寻常。它是一个&#34;事实&#34;数据仓库中的表格#34;应用?

<强>塔内

(警告:对内部构件的大部分讨论是间接得出的,可能是不正确的。)

对于某些ALTERs,工作基本上只是在架构中。例如:在ENUM的末尾添加选项; 增加 VARCHAR的大小。

对于某些ALTERs INPLACE,处理基本上是修改数据 - 无需复制。例如:最后添加一列。

PRIMARY KEY更改(在InnoDB中)必然涉及重建包含数据的BTree;他们无法完成INPLACE

可以在不触摸(除了读取)数据的情况下完成许多次要 INDEX操作。 DROP INDEX扔掉一个BTree并进行一些元更改。 ADD INDEX读取整个表,在侧面构建索引BTree,然后宣布它的存在。 CHARACTER SETCOLLATION更改需要重建索引。

如果必须复制表,则表上存在重大锁定。任何需要读取所有数据的ALTER都会产生间接影响,因为I / O和/或CPU和/或块/行等上的简短锁定。

目前还不清楚代码是否足够智能以最有效的方式处理多任务ALTER。在一个INPLACE传递中添加8列应该,但是如果它使代码太复杂,那么的操作可能会转换为 COPY

可能多任务ALTER会做最差的事情。案件。例如,更改PRIMARY KEY和扩充ENUM只会在一个COPY中执行。由于COPY是完成所有ALTERs的原始方式,因此现在已经过很好的调试和优化。 (但这是缓慢和侵入性的。)

COPY实现起来非常简单,主要涉及现有原语:

  1. 锁定real所以没有人写信
  2. CREATE TABLE new LIKE real;
  3. ALTER TABLE new ... - 无论你要求什么
  4. real的所有行复制到new - 这是缓慢的部分
  5. RENAME TABLE real TO old, new TO real; - 快速,原子等
  6. 解锁
  7. DROP TABLE old;
  8. INPLACE更复杂,因为它必须决定许多不同的算法和锁定级别。 DEFAULT如果无法COPY,则INPLACE必须向import cfscrape, re, os, time from bs4 import BeautifulSoup cc = open('cookie.txt').read() mybbuser, sid = cc.split(':') MainScrapper = cfscrape.create_scraper() def substring_after(string, delim,back): return string.partition(delim)[back] suspect = raw_input('User ID: ') def reputationCheck(userid): reputationlist = [] r = MainScrapper.get('https://v3rmillion.net/reputation.php?uid={}&show=positive'.format(userid), cookies={'mybbuser': mybbuser,'sid': sid}) soup = BeautifulSoup(r.text, 'html.parser') reputations = soup.find_all('a', href=re.compile("member\.php\?action=profile\&uid=(\d+)")) for reputation in reputations: reputationlist = reputationlist + [substring_after(reputation['href'],'uid=', 2)] if soup.find('span', {'class' : 'pages'}): pages = soup.find('span', {'class' : 'pages'}).text pages = substring_after(pages, '(', 2) pages = substring_after(pages, '):', 0) soup = BeautifulSoup(r.text, 'html.parser') for x in range(1, (int(pages))): r = MainScrapper.get('https://v3rmillion.net/reputation.php?uid={}'.format(userid) + '&show=positive&page={}'.format(x + 1), cookies={'mybbuser': mybbuser,'sid': sid}) soup = BeautifulSoup(r.text, 'html.parser') reputations = soup.find_all('a', href=re.compile("member\.php\?action=profile\&uid=(\d+)")) for reputation in reputations: if not reputation == suspect: reputationlist = reputationlist + [substring_after(reputation['href'],'uid=', 2)] for userids in reputationlist: if not str(userids) == str(suspect): victim = [] r = MainScrapper.get('https://v3rmillion.net/reputation.php?uid={}'.format(userids) + '&show=positive', cookies={'mybbuser': mybbuser,'sid': sid}) soup = BeautifulSoup(r.text, 'html.parser') reputations = soup.find_all('a', href=re.compile("member\.php\?action=profile\&uid=(\d+)")) for reputation in reputations: if substring_after(reputation['href'],'uid=', 2) == str(suspect): print(str(userids) + 'exchanged reputation with ' + str(suspect)) else: pass 发送。