<p>&nbsp;</p> <p>&nbsp;</p> <div> <div> <div> <p>首先要说明pt-online-schema-change工具并不是说修改表结构的时候不上锁,通常我们说的锁一般包含innodb 行锁和MDL lock。而pt-online-schema-change工具就是将某些使用COPY算法的DDL操作使用DML操作来代替,换句话说就是使用Innodb row锁来代替MDL lock,因为MySQL原生的COPY算法的DDL会在MDL lock SNW这个类型保护下完整个表复制操作,整个复制过程中是不允许DML操作,因此造成了我们COPY算法的DDL堵塞线程正常的现象,当然哪些DDL可以online进行可以参考官方文档online ddl一节。整个pt-online-schema-change工具修改过程中,只会在rename阶段才会上MDL LOCK的X锁,但是rename操作一般非常快速。</p> <p>我们大概看一下pt-online-schema-change的工作方式,这个实际上开启genrnal log就能看出来下面是重点步骤(我的表名叫做testpt_osc):</p> <ul> <li>首先定义出新表</li> </ul> <blockquote> <p>CREATE TABLE <code>test</code>.<code>_testpt_osc_new</code> (<br> <code>id</code> int(11) NOT NULL,<br> <code>name</code> varchar(20) DEFAULT NULL,<br> PRIMARY KEY (<code>id</code>)<br> ) ENGINE=InnoDB DEFAULT CHARSET=utf8<br> ALTER TABLE <code>test</code>.<code>_testpt_osc_new</code> add index name_index(name)</p> </blockquote> <ul> <li>定义三个触发器</li> </ul> <blockquote> <p>delete 触发器:<br> CREATE TRIGGER <code>pt_osc_test_testpt_osc_del</code><br> AFTER DELETE ON <code>test</code>.<code>testpt_osc</code><br> FOR EACH ROW<br> DELETE IGNORE FROM <code>test</code>.<code>_testpt_osc_new</code><br> WHERE <code>test</code>.<code>_testpt_osc_new</code>.<code>id</code> &lt;=&gt; OLD.<code>id</code></p> </blockquote> <blockquote> <p>update 触发器:<br> CREATE TRIGGER <code>pt_osc_test_testpt_osc_upd</code><br> AFTER UPDATE ON <code>test</code>.<code>testpt_osc</code><br> FOR EACH ROW<br> BEGIN<br> DELETE IGNORE FROM <code>test</code>.<code>_testpt_osc_new</code><br> WHERE !(OLD.<code>id</code> &lt;=&gt; NEW.<code>id</code>)<br> AND <code>test</code>.<code>_testpt_osc_new</code>.<code>id</code> &lt;=&gt; OLD.<code>id</code>;<br> REPLACE INTO <code>test</code>.<code>_testpt_osc_new</code> (<code>id</code>, <code>name</code>) VALUES<br> (NEW.<code>id</code>, NEW.<code>name</code>);<br> END</p> </blockquote> <blockquote> <p>insert 触发器:<br> CREATE TRIGGER <code>pt_osc_test_testpt_osc_ins</code><br> AFTER INSERT ON <code>test</code>.<code>testpt_osc</code><br> FOR EACH ROW<br> REPLACE INTO <code>test</code>.<code>_testpt_osc_new</code> (<code>id</code>, <code>name</code>) VALUES<br> (NEW.<code>id</code>, NEW.<code>name</code>)</p> </blockquote> <ul> <li>使用分块(chunk)拷贝的方式</li> </ul> <blockquote> <p>首先需要插入数据的确认上界:<br> SELECT /<em>!40001 SQL_NO_CACHE <em>/ <code>id</code> FROM <code>test</code>.<code>testpt_osc</code> FORCE INDEX(<code>PRIMARY</code>)<br> WHERE ((<code>id</code> &gt;= '1')) ORDERBY <code>id</code> LIMIT 1999, 2 /</em>next chunk boundary</em>/</p> </blockquote> <blockquote> <p>然后插入:<br> INSERT LOW_PRIORITY IGNORE INTO <code>test</code>.<code>_testpt_osc_new</code> (<code>id</code>, <code>name</code>)<br> SELECT <code>id</code>, <code>name</code> FROM <code>test</code>.<code>testpt_osc</code> FORCE INDEX(<code>PRIMARY</code>)<br> WHERE ((<code>id</code> &gt;= '1')) AND ((<code>id</code> &lt;= '2000')) LOCK IN SHARE MODE</p> </blockquote> <ul> <li>最终进行表的重新命名</li> </ul> <blockquote> <p>使用RENAME TABLE <code>test</code>.<code>tp1</code> TO <code>test</code>.<code>_tp1_old</code>, <code>test</code>.<code>_tp1_new</code> TO <code>test</code>.<code>tp1</code><br> 进程重新命名。</p> </blockquote> <p>从整个过程来讲需要注意的几个地方:</p> <ol> <li>对于delete和update触发器来讲,delete数据均使用了IGNORE进行修饰,因此即便数据还没有拷贝到新表也不会引发错误。</li> <li>对于update和insert触发器来讲,均使用了replace这种操作来进行,因此如果数据还没有拷贝到新表那么将插入到新表中,如果数据已经拷贝到新表那么将会修改其中的值。因此新表中总是保留的最新的数据。</li> <li>对于分块拷贝数据而言,使用是insert ignore 新表 select 老表 LOCK S 的方式,因此对于触发器插入的最新值,是不会进行修改的也不会报错。打个比方chunk为200 当前拷贝数据到了1000行,但是我们手动修改了第2000行的数据,那么第2000行将会在update触发器的作用下提前插入到新表中,当拷贝数据来到这一行的时候因为使用了ignore则不会重复行的错误,并且数据是最新的。其次每次insert select操作是一个单独的事务。</li> <li>insert ignore 新表 select 老表 LOCK S 的方式 操作存在对新表中加自增锁的可能,这取决于你的参数设置。</li> <li>对于触发器而言,原始语句和触发语句被包裹在一个事务里面,也就是说对于任何一个DML语句而言,修改老表和新表的数据需要的行锁将会在一个事务中存在。</li> <li>pt-online-schema-change 生成的binlog和redo都会比online DDL大得多,效率上讲应该低于online DDL。</li> <li>由于replace操作的存在,因此pt-online-schema-change将会依赖主键或者唯一键,否则将不能工作。</li> </ol> <p>我们可以看到整个过程中有如下的重点知识点:</p> <ul> <li>触发器和事务</li> <li>Insert ignore/replace语法</li> <li>自增死锁的发生</li> </ul> <p>其次对于第4和第5点来讲,有出现死锁的可能。下面我们分别讨论。</p> <h3>二、触发器与事务</h3> <p>在pt-online-schema-change中,触发器占据了重要的地位,我们需要了解一下触发器和事务之间的关系。我们常用的触发器包含了before和after触发器,代表着对原表进行DML操作前或者后进行其它的操作,下面是我定义的两个测试的触发器如下:</p> <div class="_2Uzcx_"> <button class="VJbwyy" type="button"></button> <pre class="line-numbers language-cpp"><code class=" language-cpp">CREATE TRIGGER testbef BEFORE INSERT ON t1 FOR EACH ROW BEGIN INSERT INTO t2 <span class="token function">values<span class="token punctuation">(<span class="token keyword">new<span class="token punctuation">.id<span class="token punctuation">)<span class="token punctuation">; END<span class="token punctuation">; CREATE TRIGGER testaft after INSERT ON t1 FOR EACH ROW BEGIN INSERT INTO t3 <span class="token function">values<span class="token punctuation">(<span class="token keyword">new<span class="token punctuation">.id<span class="token punctuation">)<span class="token punctuation">; END<span class="token punctuation">; </span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre> </div> <p>显然如果对t1表进行数据插入,那么会在之前向t2表插入一条数据,然后在之后向t3插入一条数据,这一点可以通过函数调用trace进行验证如下:</p> <div class="_2Uzcx_"> <button class="VJbwyy" type="button"></button> <pre class="line-numbers language-ruby"><code class=" language-ruby"><span class="token punctuation">[root<span class="token variable">@ora12ctest mysql<span class="token punctuation">]<span class="token comment"># cat -n tri2.trace |grep row_ins <span class="token number">970 <span class="token constant">T@<span class="token number">3<span class="token punctuation">: <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">&gt;row_ins <span class="token number">971 <span class="token constant">T@<span class="token number">3<span class="token punctuation">: <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| row_ins<span class="token punctuation">: table<span class="token punctuation">: test<span class="token operator">/t2 向t2表插入数据 <span class="token punctuation">.<span class="token punctuation">.<span class="token punctuation">. <span class="token number">1406 <span class="token constant">T@<span class="token number">3<span class="token punctuation">: <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">&gt;row_ins <span class="token number">1407 <span class="token constant">T@<span class="token number">3<span class="token punctuation">: <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| row_ins<span class="token punctuation">: table<span class="token punctuation">: test<span class="token operator">/t1 向t1表插入数据 <span class="token punctuation">.<span class="token punctuation">.<span class="token punctuation">. <span class="token number">1779 <span class="token constant">T@<span class="token number">3<span class="token punctuation">: <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">&gt;row_ins <span class="token number">1780 <span class="token constant">T@<span class="token number">3<span class="token punctuation">: <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| <span class="token operator">| row_ins<span class="token punctuation">: table<span class="token punctuation">: test<span class="token operator">/t3 向t3表插入数据 <span class="token punctuation">.<span class="token punctuation">.<span class="token punctuation">. </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre> </div> <p>这里就能够看到顺序了,其次我们还需要知道这些所有的操作会包裹在一个事务里面,这一点也可以通过函数调用trace进行验证,还可以使用binlog进行验证,下面是一次调用的binlog信息:</p> <div class="_2Uzcx_"> <button class="VJbwyy" type="button"></button> <pre class="line-numbers language-csharp"><code class=" language-csharp"><span class="token preprocessor property"># at 194 (这里是GTID EVENT事务开始) <span class="token preprocessor property">#200212 17:23:16 server id 1903313 end_log_pos 259 CRC32 0x4ff6735e GTID last_committed=0 sequence_number=1 rbr_only=yes <span class="token comment">/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*/<span class="token comment">/*!*/<span class="token punctuation">; SET @@SESSION<span class="token punctuation">.GTID_NEXT<span class="token operator">= <span class="token string">'92008a52-4b7d-11ea-9ec6-000c29c8aca8:202'<span class="token comment">/*!*/<span class="token punctuation">; <span class="token preprocessor property"># at 259 <span class="token preprocessor property">#200212 17:23:16 server id 1903313 end_log_pos 331 CRC32 0x1ebd3446 Query thread_id=3 exec_time=0 error_code=0 <span class="token punctuation">.<span class="token punctuation">.<span class="token punctuation">. BEGIN <span class="token comment">/*!*/<span class="token punctuation">; <span class="token preprocessor property"># at 331 <span class="token preprocessor property">#200212 17:23:16 server id 1903313 end_log_pos 384 CRC32 0xe748dc3a Rows_query <span class="token preprocessor property"># INSERT INTO t2 values(new.id) <span class="token preprocessor property"># at 384 <span class="token preprocessor property">#200212 17:23:16 server id 1903313 end_log_pos 429 CRC32 0x093c5fe3 Table_map: `test`.`t1` mapped to number 108 <span class="token preprocessor property"># at 429 <span class="token preprocessor property">#200212 17:23:16 server id 1903313 end_log_pos 474 CRC32 0x92691238 Table_map: `test`.`t2` mapped to number 110 <span class="token preprocessor property"># at 474 <span class="token preprocessor property">#200212 17:23:16 server id 1903313 end_log_pos 519 CRC32 0x5b9a710f Table_map: `test`.`t3` mapped to number 111 <span class="token preprocessor property"># at 519 <span class="token preprocessor property">#200212 17:23:16 server id 1903313 end_log_pos 559 CRC32 0xe41b1119 Write_rows: table id 110 <span class="token preprocessor property"># at 559 <span class="token preprocessor property">#200212 17:23:16 server id 1903313 end_log_pos 599 CRC32 0x36c3511c Write_rows: table id 108 <span class="token preprocessor property"># at 599 <span class="token preprocessor property">#200212 17:23:16 server id 1903313 end_log_pos 639 CRC32 0xa68b9ae6 Write_rows: table id 111 flags: STMT_END_F <span class="token preprocessor property">### INSERT INTO `test`.`t2` <span class="token preprocessor property">### SET <span class="token preprocessor property">### @1=11000 <span class="token comment">/* INT meta=0 nullable=0 is_null=0 */ <span class="token preprocessor property">### INSERT INTO `test`.`t1` <span class="token preprocessor property">### SET <span class="token preprocessor property">### @1=11000 <span class="token comment">/* INT meta=0 nullable=1 is_null=0 */ <span class="token preprocessor property">### INSERT INTO `test`.`t3` <span class="token preprocessor property">### SET <span class="token preprocessor property">### @1=11000 <span class="token comment">/* INT meta=0 nullable=0 is_null=0 */ <span class="token preprocessor property"># at 639 (这里是XID EVENT事务提交) <span class="token preprocessor property">#200212 17:23:16 server id 1903313 end_log_pos 670 CRC32 0xbbb6547b Xid = 19 COMMIT<span class="token comment">/*!*/<span class="token punctuation">; </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre> </div> <p>这里我们使用binlog不仅验证了执行顺序并且还验证了所有操作都包含在一个事务里面。<strong>既然所有的语句都包裹在一个事务里面,那么加锁的范围就更大了,这不仅关系到本身的DML操作表,并且还关系到触发语句的相关表,需要额外注意。</strong></p> <p>其次所有语句不仅包裹在一个事务里面,并且共享一个错误返回接口,那么如下的错误:</p> <div class="_2Uzcx_"> <button class="VJbwyy" type="button"></button> <pre class="line-numbers language-csharp"><code class=" language-csharp">mysql<span class="token operator">&gt; <span class="token keyword">select <span class="token function">count<span class="token punctuation">(<span class="token operator">*<span class="token punctuation">) <span class="token keyword">from t1<span class="token punctuation">; <span class="token operator">+<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">+ <span class="token operator">| <span class="token function">count<span class="token punctuation">(<span class="token operator">*<span class="token punctuation">) <span class="token operator">| <span class="token operator">+<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">+ <span class="token operator">| <span class="token number">0 <span class="token operator">| <span class="token operator">+<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">+ <span class="token number">1 row <span class="token keyword">in <span class="token keyword">set <span class="token punctuation">(<span class="token number">0.00 sec<span class="token punctuation">) mysql<span class="token operator">&gt; insert <span class="token keyword">into t1 <span class="token function">values<span class="token punctuation">(<span class="token number">1<span class="token punctuation">)<span class="token punctuation">; <span class="token class-name">ERROR <span class="token number">1062 <span class="token punctuation">(<span class="token number">23000<span class="token punctuation">)<span class="token punctuation">: <span class="token class-name">Duplicate entry <span class="token string">'1' <span class="token keyword">for key <span class="token string">'PRIMARY' mysql<span class="token operator">&gt; </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre> </div> <p>我们惊讶的发现t1表一条数据都没有,但是居然返回重复的行。<strong>原因就在于虽然t1表没有数据,但是t2或者t3表有违反唯一性检查的可能,因此返回了错误,错误由统一的接口返回给客户端。</strong></p> <p>最后触发器会导致处理逻辑混乱,<strong>尽量避免使用触发器</strong>。</p> <h3>三、Insert ignore/replace语法</h3> <p>关于ignore语法我们以insert ignore语法为例,一般来讲如果遇到重复行insert ignore语***通过忽略重复值错误的方式进行跳过,这实际上和replace的处理方式一致,但是replace不同的是如果遇到重复行不是进行忽略,而是执行的delete然后执行insert操作。换句话说他们的触发形式一致,但是触发后执行的行为是不同的,下面我们就来看看。</p> <p>首先对于insert语句来讲我们需要定位到需要插入的位置,这部分略过。</p> <h5>1、进行重复行判断操作</h5> <p>这一步对于主键/唯一索引 而言需要判断是否已经有重复的行。其判断标准基本都是通过插入的值进行索引定位,然后判断定位游标的值是否和需要插入值相同,下面是栈帧:</p> <blockquote> <p>主键:</p> </blockquote> <div class="_2Uzcx_"> <button class="VJbwyy" type="button"></button> <pre class="line-numbers language-objectivec"><code class=" language-objectivec">#<span class="token number">0 row_ins_duplicate_error_in_clust <span class="token punctuation">(flags<span class="token operator">=<span class="token number">0<span class="token punctuation">, cursor<span class="token operator">=<span class="token number">0x7fffec4347d0<span class="token punctuation">, entry<span class="token operator">=<span class="token number">0x7367c00<span class="token punctuation">, thr<span class="token operator">=<span class="token number">0x7362980<span class="token punctuation">, mtr<span class="token operator">=<span class="token number">0x7fffec433fa0<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0ins<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">2273 #<span class="token number">1 <span class="token number">0x0000000001ae47d4 <span class="token keyword">in row_ins_clust_index_entry_low <span class="token punctuation">(flags<span class="token operator">=<span class="token number">0<span class="token punctuation">, mode<span class="token operator">=<span class="token number">2<span class="token punctuation">, index<span class="token operator">=<span class="token number">0x73674f0<span class="token punctuation">, n_uniq<span class="token operator">=<span class="token number">1<span class="token punctuation">, entry<span class="token operator">=<span class="token number">0x7367c00<span class="token punctuation">, n_ext<span class="token operator">=<span class="token number">0<span class="token punctuation">, thr<span class="token operator">=<span class="token number">0x7362980<span class="token punctuation">, dup_chk_only<span class="token operator">=false<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0ins<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">2555 #<span class="token number">2 <span class="token number">0x0000000001ae697a <span class="token keyword">in row_ins_clust_index_entry <span class="token punctuation">(index<span class="token operator">=<span class="token number">0x73674f0<span class="token punctuation">, entry<span class="token operator">=<span class="token number">0x7367c00<span class="token punctuation">, thr<span class="token operator">=<span class="token number">0x7362980<span class="token punctuation">, n_ext<span class="token operator">=<span class="token number">0<span class="token punctuation">, dup_chk_only<span class="token operator">=false<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0ins<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3293 #<span class="token number">3 <span class="token number">0x0000000001ae6e88 <span class="token keyword">in row_ins_index_entry <span class="token punctuation">(index<span class="token operator">=<span class="token number">0x73674f0<span class="token punctuation">, entry<span class="token operator">=<span class="token number">0x7367c00<span class="token punctuation">, thr<span class="token operator">=<span class="token number">0x7362980<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0ins<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3429 #<span class="token number">4 <span class="token number">0x0000000001ae73e2 <span class="token keyword">in row_ins_index_entry_step <span class="token punctuation">(node<span class="token operator">=<span class="token number">0x7362710<span class="token punctuation">, thr<span class="token operator">=<span class="token number">0x7362980<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0ins<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3579 #<span class="token number">5 <span class="token number">0x0000000001ae7749 <span class="token keyword">in row_ins <span class="token punctuation">(node<span class="token operator">=<span class="token number">0x7362710<span class="token punctuation">, thr<span class="token operator">=<span class="token number">0x7362980<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0ins<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3717 #<span class="token number">6 <span class="token number">0x0000000001ae7bae <span class="token keyword">in row_ins_step <span class="token punctuation">(thr<span class="token operator">=<span class="token number">0x7362980<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0ins<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3853 #<span class="token number">7 <span class="token number">0x0000000001b05f73 <span class="token keyword">in row_insert_for_mysql_using_ins_graph <span class="token punctuation">(mysql_rec<span class="token operator">=<span class="token number">0x736e7a0 <span class="token string">"\375\002"<span class="token punctuation">, prebuilt<span class="token operator">=<span class="token number">0x7362170<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0mysql<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1738 #<span class="token number">8 <span class="token number">0x0000000001b06484 <span class="token keyword">in row_insert_for_mysql <span class="token punctuation">(mysql_rec<span class="token operator">=<span class="token number">0x736e7a0 <span class="token string">"\375\002"<span class="token punctuation">, prebuilt<span class="token operator">=<span class="token number">0x7362170<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0mysql<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1859 #<span class="token number">9 <span class="token number">0x00000000019adca9 <span class="token keyword">in ha_innobase<span class="token punctuation">:<span class="token punctuation">:write_row <span class="token punctuation">(this<span class="token operator">=<span class="token number">0x736e4b0<span class="token punctuation">, record<span class="token operator">=<span class="token number">0x736e7a0 <span class="token string">"\375\002"<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/handler<span class="token operator">/ha_innodb<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">7598 #<span class="token number">10 <span class="token number">0x0000000000f67dc0 <span class="token keyword">in handler<span class="token punctuation">:<span class="token punctuation">:ha_write_row <span class="token punctuation">(this<span class="token operator">=<span class="token number">0x736e4b0<span class="token punctuation">, buf<span class="token operator">=<span class="token number">0x736e7a0 <span class="token string">"\375\002"<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/handler<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">8062 #<span class="token number">11 <span class="token number">0x00000000017cf173 <span class="token keyword">in write_record <span class="token punctuation">(thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">, table<span class="token operator">=<span class="token number">0x735afa0<span class="token punctuation">, info<span class="token operator">=<span class="token number">0x7fffec435b50<span class="token punctuation">, update<span class="token operator">=<span class="token number">0x7fffec435ad0<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_insert<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1873 #<span class="token number">12 <span class="token number">0x00000000017cc24a <span class="token keyword">in Sql_cmd_insert<span class="token punctuation">:<span class="token punctuation">:mysql_insert <span class="token punctuation">(this<span class="token operator">=<span class="token number">0x6debbc8<span class="token punctuation">, thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">, table_list<span class="token operator">=<span class="token number">0x6deb638<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_insert<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">769 #<span class="token number">13 <span class="token number">0x00000000017d2d7f <span class="token keyword">in Sql_cmd_insert<span class="token punctuation">:<span class="token punctuation">:execute <span class="token punctuation">(this<span class="token operator">=<span class="token number">0x6debbc8<span class="token punctuation">, thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_insert<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3118 #<span class="token number">14 <span class="token number">0x000000000159a70c <span class="token keyword">in mysql_execute_command <span class="token punctuation">(thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">, first_level<span class="token operator">=true<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_parse<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3596 #<span class="token number">15 <span class="token number">0x00000000015a06c0 <span class="token keyword">in mysql_parse <span class="token punctuation">(thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">, parser_state<span class="token operator">=<span class="token number">0x7fffec437610<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_parse<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">5570 #<span class="token number">16 <span class="token number">0x0000000001595283 <span class="token keyword">in dispatch_command <span class="token punctuation">(thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">, com_data<span class="token operator">=<span class="token number">0x7fffec437d80<span class="token punctuation">, command<span class="token operator">=COM_QUERY<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_parse<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1484 #<span class="token number">17 <span class="token number">0x00000000015940bc <span class="token keyword">in do_command <span class="token punctuation">(thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_parse<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1025 #<span class="token number">18 <span class="token number">0x00000000016cbf91 <span class="token keyword">in handle_connection <span class="token punctuation">(arg<span class="token operator">=<span class="token number">0x6dda360<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/conn_handler<span class="token operator">/connection_handler_per_thread<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">306 #<span class="token number">19 <span class="token number">0x0000000001921c64 <span class="token keyword">in pfs_spawn_thread <span class="token punctuation">(arg<span class="token operator">=<span class="token number">0x6d7d0f0<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/perfschema<span class="token operator">/pfs<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">2190 #<span class="token number">20 <span class="token number">0x0000003823e079d1 <span class="token keyword">in start_thread <span class="token punctuation">(<span class="token punctuation">) from <span class="token operator">/lib64<span class="token operator">/libpthread<span class="token punctuation">.so<span class="token punctuation">.<span class="token number">0 #<span class="token number">21 <span class="token number">0x0000003823ae8b6d <span class="token keyword">in clone <span class="token punctuation">(<span class="token punctuation">) from <span class="token operator">/lib64<span class="token operator">/libc<span class="token punctuation">.so<span class="token punctuation">.<span class="token number">6 </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre> </div> <blockquote> <p>二级索引唯一键</p> </blockquote> <div class="_2Uzcx_"> <button class="VJbwyy" type="button"></button> <pre class="line-numbers language-objectivec"><code class=" language-objectivec">#<span class="token number">0 row_ins_scan_sec_index_for_duplicate <span class="token punctuation">(flags<span class="token operator">=<span class="token number">0<span class="token punctuation">, index<span class="token operator">=<span class="token number">0x7366e10<span class="token punctuation">, entry<span class="token operator">=<span class="token number">0x7367ca8<span class="token punctuation">, thr<span class="token operator">=<span class="token number">0x7362980<span class="token punctuation">, s_latch<span class="token operator">=false<span class="token punctuation">, mtr<span class="token operator">=<span class="token number">0x7fffec434020<span class="token punctuation">, offsets_heap<span class="token operator">=<span class="token number">0x7389038<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0ins<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">2050 #<span class="token number">1 <span class="token number">0x0000000001ae5d35 <span class="token keyword">in row_ins_sec_index_entry_low <span class="token punctuation">(flags<span class="token operator">=<span class="token number">0<span class="token punctuation">, mode<span class="token operator">=<span class="token number">2<span class="token punctuation">, index<span class="token operator">=<span class="token number">0x7366e10<span class="token punctuation">, offsets_heap<span class="token operator">=<span class="token number">0x7389038<span class="token punctuation">, heap<span class="token operator">=<span class="token number">0x7368538<span class="token punctuation">, entry<span class="token operator">=<span class="token number">0x7367ca8<span class="token punctuation">, trx_id<span class="token operator">=<span class="token number">0<span class="token punctuation">, thr<span class="token operator">=<span class="token number">0x7362980<span class="token punctuation">, dup_chk_only<span class="token operator">=false<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0ins<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3033 #<span class="token number">2 <span class="token number">0x0000000001ae6cea <span class="token keyword">in row_ins_sec_index_entry <span class="token punctuation">(index<span class="token operator">=<span class="token number">0x7366e10<span class="token punctuation">, entry<span class="token operator">=<span class="token number">0x7367ca8<span class="token punctuation">, thr<span class="token operator">=<span class="token number">0x7362980<span class="token punctuation">, dup_chk_only<span class="token operator">=false<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0ins<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3382 #<span class="token number">3 <span class="token number">0x0000000001ae6ea6 <span class="token keyword">in row_ins_index_entry <span class="token punctuation">(index<span class="token operator">=<span class="token number">0x7366e10<span class="token punctuation">, entry<span class="token operator">=<span class="token number">0x7367ca8<span class="token punctuation">, thr<span class="token operator">=<span class="token number">0x7362980<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0ins<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3431 #<span class="token number">4 <span class="token number">0x0000000001ae73e2 <span class="token keyword">in row_ins_index_entry_step <span class="token punctuation">(node<span class="token operator">=<span class="token number">0x7362710<span class="token punctuation">, thr<span class="token operator">=<span class="token number">0x7362980<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0ins<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3579 #<span class="token number">5 <span class="token number">0x0000000001ae7749 <span class="token keyword">in row_ins <span class="token punctuation">(node<span class="token operator">=<span class="token number">0x7362710<span class="token punctuation">, thr<span class="token operator">=<span class="token number">0x7362980<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0ins<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3717 #<span class="token number">6 <span class="token number">0x0000000001ae7bae <span class="token keyword">in row_ins_step <span class="token punctuation">(thr<span class="token operator">=<span class="token number">0x7362980<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0ins<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3853 #<span class="token number">7 <span class="token number">0x0000000001b05f73 <span class="token keyword">in row_insert_for_mysql_using_ins_graph <span class="token punctuation">(mysql_rec<span class="token operator">=<span class="token number">0x736e7a0 <span class="token string">"\375\003"<span class="token punctuation">, prebuilt<span class="token operator">=<span class="token number">0x7362170<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0mysql<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1738 #<span class="token number">8 <span class="token number">0x0000000001b06484 <span class="token keyword">in row_insert_for_mysql <span class="token punctuation">(mysql_rec<span class="token operator">=<span class="token number">0x736e7a0 <span class="token string">"\375\003"<span class="token punctuation">, prebuilt<span class="token operator">=<span class="token number">0x7362170<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0mysql<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1859 #<span class="token number">9 <span class="token number">0x00000000019adca9 <span class="token keyword">in ha_innobase<span class="token punctuation">:<span class="token punctuation">:write_row <span class="token punctuation">(this<span class="token operator">=<span class="token number">0x736e4b0<span class="token punctuation">, record<span class="token operator">=<span class="token number">0x736e7a0 <span class="token string">"\375\003"<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/handler<span class="token operator">/ha_innodb<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">7598 #<span class="token number">10 <span class="token number">0x0000000000f67dc0 <span class="token keyword">in handler<span class="token punctuation">:<span class="token punctuation">:ha_write_row <span class="token punctuation">(this<span class="token operator">=<span class="token number">0x736e4b0<span class="token punctuation">, buf<span class="token operator">=<span class="token number">0x736e7a0 <span class="token string">"\375\003"<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/handler<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">8062 #<span class="token number">11 <span class="token number">0x00000000017cf173 <span class="token keyword">in write_record <span class="token punctuation">(thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">, table<span class="token operator">=<span class="token number">0x735afa0<span class="token punctuation">, info<span class="token operator">=<span class="token number">0x7fffec435b50<span class="token punctuation">, update<span class="token operator">=<span class="token number">0x7fffec435ad0<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_insert<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1873 #<span class="token number">12 <span class="token number">0x00000000017cc24a <span class="token keyword">in Sql_cmd_insert<span class="token punctuation">:<span class="token punctuation">:mysql_insert <span class="token punctuation">(this<span class="token operator">=<span class="token number">0x6debbc8<span class="token punctuation">, thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">, table_list<span class="token operator">=<span class="token number">0x6deb638<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_insert<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">769 #<span class="token number">13 <span class="token number">0x00000000017d2d7f <span class="token keyword">in Sql_cmd_insert<span class="token punctuation">:<span class="token punctuation">:execute <span class="token punctuation">(this<span class="token operator">=<span class="token number">0x6debbc8<span class="token punctuation">, thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_insert<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3118 #<span class="token number">14 <span class="token number">0x000000000159a70c <span class="token keyword">in mysql_execute_command <span class="token punctuation">(thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">, first_level<span class="token operator">=true<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_parse<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3596 #<span class="token number">15 <span class="token number">0x00000000015a06c0 <span class="token keyword">in mysql_parse <span class="token punctuation">(thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">, parser_state<span class="token operator">=<span class="token number">0x7fffec437610<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_parse<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">5570 #<span class="token number">16 <span class="token number">0x0000000001595283 <span class="token keyword">in dispatch_command <span class="token punctuation">(thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">, com_data<span class="token operator">=<span class="token number">0x7fffec437d80<span class="token punctuation">, command<span class="token operator">=COM_QUERY<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_parse<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1484 #<span class="token number">17 <span class="token number">0x00000000015940bc <span class="token keyword">in do_command <span class="token punctuation">(thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_parse<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1025 #<span class="token number">18 <span class="token number">0x00000000016cbf91 <span class="token keyword">in handle_connection <span class="token punctuation">(arg<span class="token operator">=<span class="token number">0x6dda360<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/conn_handler<span class="token operator">/connection_handler_per_thread<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">306 #<span class="token number">19 <span class="token number">0x0000000001921c64 <span class="token keyword">in pfs_spawn_thread <span class="token punctuation">(arg<span class="token operator">=<span class="token number">0x6d7d0f0<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/perfschema<span class="token operator">/pfs<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">2190 #<span class="token number">20 <span class="token number">0x0000003823e079d1 <span class="token keyword">in start_thread <span class="token punctuation">(<span class="token punctuation">) from <span class="token operator">/lib64<span class="token operator">/libpthread<span class="token punctuation">.so<span class="token punctuation">.<span class="token number">0 #<span class="token number">21 <span class="token number">0x0000003823ae8b6d <span class="token keyword">in clone <span class="token punctuation">(<span class="token punctuation">) from <span class="token operator">/lib64<span class="token operator">/libc<span class="token punctuation">.so<span class="token punctuation">.<span class="token number">6 </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre> </div> <p>如果存在重复的行,这需要进行判断了:</p> <ul> <li>如果重复的行正在被其他事务持有,那么需要进行进行隐试锁转换,主键的转换操作如下:</li> </ul> <div class="_2Uzcx_"> <button class="VJbwyy" type="button"></button> <pre class="line-numbers language-php"><code class=" language-php"><span class="token operator">-<span class="token operator">&gt;<span class="token property">lock_clust_rec_read_check_and_lock <span class="token operator">-<span class="token operator">&gt;<span class="token property">lock_rec_convert_impl_to_expl <span class="token operator">-<span class="token operator">&gt;<span class="token property">lock_rec_convert_impl_to_expl_for_trx </span></span></span></span></span></span></span></span></span></code></pre> </div> <p>因为我们知道通常insert锁并不会建立显示的锁。对于如果出现了重复的行,持有重复行数据的事务并没有提交或者回滚,需要其事务完成提交或者回滚,然后再进行相应的抛错或者继续插入。需要注意的是对于replace/insert on dup 在进行唯一性检查的时候,通常加的LOCK_S锁,而其他操作通常加的是 LOCK_X。</p> <ul> <li>如果重复的行没有其他事务持有,那么抛出重复行错误,但是注意这里的错误不是返回给客户端的错误,是内部错误HA_ERR_FOUND_DUPP_KEY,这个错误在Innodb层叫做DB_DUPLICATE_KEY(convert_error_code_to_mysql)。如何处理这个错误就和相应的语法有关了。</li> </ul> <p>当然如果没有重复的行,那么接下来就可以继续进行insert插入操作了,Insert ignore/replace实现都是进行insert操作。如果有重复行呢?那么接下来进行分析。</p> <p>这里我们也很明白了,对于了insert ignore/replace是通过主键/唯一键进行判断是否重复行的,具体点来说就是如何处理错误HA_ERR_FOUND_DUPP_KEY。 <strong>如果表中一个能够判断唯一性的索引都没有,那么即便2条数据一模一样也不会标记为重复行,视为2条不同的数据</strong>,当然insert on dup 这里也是同样的逻辑。<br> 在进行唯一性检测的时候,会先检查主键的唯一性,然后依次检查各个唯一索引的唯一性是否满足。</p> <h5>2、可能的回滚操作</h5> <p>首先对于多行插入和insert select来讲,每次innodb层插入的行数为1行,我们应该牢牢树立以行为单位的处理流程,我们可以在函数Sql_cmd_insert::mysql_insert 中找到 一个大的while 循环,这就是处理的循环。</p> <p>我们也需要明白,进行判断唯一性的时候是先判断主键的唯一性,如果满足则插入主键数据,然后依次判断二级唯一索引,如果满足则进行插入。这里涉及到一个问题,如果主键数据插入了,但是二级唯一索引由于违法唯一性那么,前面主键插入的数据是需要回滚的。再或者我们执行的insert select操作,其中前面的一些行不违反唯一性插入了,但是随后的某行违法了唯一性,那么前面插入的数据也是需要回滚的。函数row_insert_for_mysql_using_ins_graph 中进行这种逻辑处理。</p> <p>回滚栈帧:</p> <div class="_2Uzcx_"> <button class="VJbwyy" type="button"></button> <pre class="line-numbers language-objectivec"><code class=" language-objectivec">#<span class="token number">0 row_undo_ins <span class="token punctuation">(node<span class="token operator">=<span class="token number">0x73685c0<span class="token punctuation">, thr<span class="token operator">=<span class="token number">0x73671e8<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0uins<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">466 #<span class="token number">1 <span class="token number">0x0000000001b5d918 <span class="token keyword">in row_undo <span class="token punctuation">(node<span class="token operator">=<span class="token number">0x73685c0<span class="token punctuation">, thr<span class="token operator">=<span class="token number">0x73671e8<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0undo<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">327 #<span class="token number">2 <span class="token number">0x0000000001b5dbae <span class="token keyword">in row_undo_step <span class="token punctuation">(thr<span class="token operator">=<span class="token number">0x73671e8<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0undo<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">411 #<span class="token number">3 <span class="token number">0x0000000001ab1847 <span class="token keyword">in que_thr_step <span class="token punctuation">(thr<span class="token operator">=<span class="token number">0x73671e8<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/que<span class="token operator">/que0que<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1047 #<span class="token number">4 <span class="token number">0x0000000001ab1a63 <span class="token keyword">in que_run_threads_low <span class="token punctuation">(thr<span class="token operator">=<span class="token number">0x73671e8<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/que<span class="token operator">/que0que<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1111 #<span class="token number">5 <span class="token number">0x0000000001ab1c25 <span class="token keyword">in que_run_threads <span class="token punctuation">(thr<span class="token operator">=<span class="token number">0x73671e8<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/que<span class="token operator">/que0que<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1151 #<span class="token number">6 <span class="token number">0x0000000001bc622b <span class="token keyword">in trx_rollback_to_savepoint_low <span class="token punctuation">(trx<span class="token operator">=<span class="token number">0x7fffedc5b8c0<span class="token punctuation">, savept<span class="token operator">=<span class="token number">0x7fffec434b60<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/trx<span class="token operator">/trx0roll<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">118 #<span class="token number">7 <span class="token number">0x0000000001bc64d2 <span class="token keyword">in trx_rollback_to_savepoint <span class="token punctuation">(trx<span class="token operator">=<span class="token number">0x7fffedc5b8c0<span class="token punctuation">, savept<span class="token operator">=<span class="token number">0x7fffec434b60<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/trx<span class="token operator">/trx0roll<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">159 #<span class="token number">8 <span class="token number">0x0000000001b03b92 <span class="token keyword">in row_mysql_handle_errors <span class="token punctuation">(new_err<span class="token operator">=<span class="token number">0x7fffec434b5c<span class="token punctuation">, trx<span class="token operator">=<span class="token number">0x7fffedc5b8c0<span class="token punctuation">, thr<span class="token operator">=<span class="token number">0x7362980<span class="token punctuation">, savept<span class="token operator">=<span class="token number">0x7fffec434b60<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0mysql<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">767 #<span class="token number">9 <span class="token number">0x0000000001b05ff2 <span class="token keyword">in row_insert_for_mysql_using_ins_graph <span class="token punctuation">(mysql_rec<span class="token operator">=<span class="token number">0x736e7a0 <span class="token string">"\375\n"<span class="token punctuation">, prebuilt<span class="token operator">=<span class="token number">0x7362170<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0mysql<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1752 #<span class="token number">10 <span class="token number">0x0000000001b06484 <span class="token keyword">in row_insert_for_mysql <span class="token punctuation">(mysql_rec<span class="token operator">=<span class="token number">0x736e7a0 <span class="token string">"\375\n"<span class="token punctuation">, prebuilt<span class="token operator">=<span class="token number">0x7362170<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/row<span class="token operator">/row0mysql<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1859 #<span class="token number">11 <span class="token number">0x00000000019adca9 <span class="token keyword">in ha_innobase<span class="token punctuation">:<span class="token punctuation">:write_row <span class="token punctuation">(this<span class="token operator">=<span class="token number">0x736e4b0<span class="token punctuation">, record<span class="token operator">=<span class="token number">0x736e7a0 <span class="token string">"\375\n"<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/innobase<span class="token operator">/handler<span class="token operator">/ha_innodb<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">7598 #<span class="token number">12 <span class="token number">0x0000000000f67dc0 <span class="token keyword">in handler<span class="token punctuation">:<span class="token punctuation">:ha_write_row <span class="token punctuation">(this<span class="token operator">=<span class="token number">0x736e4b0<span class="token punctuation">, buf<span class="token operator">=<span class="token number">0x736e7a0 <span class="token string">"\375\n"<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/handler<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">8062 #<span class="token number">13 <span class="token number">0x00000000017cf173 <span class="token keyword">in write_record <span class="token punctuation">(thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">, table<span class="token operator">=<span class="token number">0x735afa0<span class="token punctuation">, info<span class="token operator">=<span class="token number">0x7fffec435b50<span class="token punctuation">, update<span class="token operator">=<span class="token number">0x7fffec435ad0<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_insert<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1873 #<span class="token number">14 <span class="token number">0x00000000017cc24a <span class="token keyword">in Sql_cmd_insert<span class="token punctuation">:<span class="token punctuation">:mysql_insert <span class="token punctuation">(this<span class="token operator">=<span class="token number">0x6debbc8<span class="token punctuation">, thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">, table_list<span class="token operator">=<span class="token number">0x6deb638<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_insert<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">769 #<span class="token number">15 <span class="token number">0x00000000017d2d7f <span class="token keyword">in Sql_cmd_insert<span class="token punctuation">:<span class="token punctuation">:execute <span class="token punctuation">(this<span class="token operator">=<span class="token number">0x6debbc8<span class="token punctuation">, thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_insert<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3118 #<span class="token number">16 <span class="token number">0x000000000159a70c <span class="token keyword">in mysql_execute_command <span class="token punctuation">(thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">, first_level<span class="token operator">=true<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_parse<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">3596 #<span class="token number">17 <span class="token number">0x00000000015a06c0 <span class="token keyword">in mysql_parse <span class="token punctuation">(thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">, parser_state<span class="token operator">=<span class="token number">0x7fffec437610<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_parse<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">5570 #<span class="token number">18 <span class="token number">0x0000000001595283 <span class="token keyword">in dispatch_command <span class="token punctuation">(thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">, com_data<span class="token operator">=<span class="token number">0x7fffec437d80<span class="token punctuation">, command<span class="token operator">=COM_QUERY<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_parse<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1484 #<span class="token number">19 <span class="token number">0x00000000015940bc <span class="token keyword">in do_command <span class="token punctuation">(thd<span class="token operator">=<span class="token number">0x6dd5660<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/sql_parse<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">1025 #<span class="token number">20 <span class="token number">0x00000000016cbf91 <span class="token keyword">in handle_connection <span class="token punctuation">(arg<span class="token operator">=<span class="token number">0x6dda360<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/sql<span class="token operator">/conn_handler<span class="token operator">/connection_handler_per_thread<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">306 #<span class="token number">21 <span class="token number">0x0000000001921c64 <span class="token keyword">in pfs_spawn_thread <span class="token punctuation">(arg<span class="token operator">=<span class="token number">0x6d7d0f0<span class="token punctuation">) at <span class="token operator">/mysql<span class="token operator">/mysql<span class="token operator">-<span class="token number">5.7<span class="token number">.26<span class="token operator">/storage<span class="token operator">/perfschema<span class="token operator">/pfs<span class="token punctuation">.cc<span class="token punctuation">:<span class="token number">2190 #<span class="token number">22 <span class="token number">0x0000003823e079d1 <span class="token keyword">in start_thread <span class="token punctuation">(<span class="token punctuation">) from <span class="token operator">/lib64<span class="token operator">/libpthread<span class="token punctuation">.so<span class="token punctuation">.<span class="token number">0 #<span class="token number">23 <span class="token number">0x0000003823ae8b6d <span class="token keyword">in clone <span class="token punctuation">(<span class="token punctuation">) from <span class="token operator">/lib64<span class="token operator">/libc<span class="token punctuation">.so<span class="token punctuation">.<span class="token number">6 </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre> </div> <h6>3、对重复错误HA_ERR_FOUND_DUPP_KEY 的处理操作</h6> <p>如果有重复的行并且产生了错误HA_ERR_FOUND_DUPP_KEY ,那么就不能进行insert 操作了,这里就会根据不同的语法进行不同的操作了。我们在函数(write_record )中可以找到这种分支处理逻辑。</p> <p>实际上在处理重复行错误的时候,在内部分为了3种方式如下:</p> <div class="_2Uzcx_"> <button class="VJbwyy" type="button"></button> <pre class="line-numbers language-rust"><code class=" language-rust"><span class="token keyword">enum enum_duplicates <span class="token punctuation">{ DUP_ERROR<span class="token punctuation">, DUP_REPLACE<span class="token punctuation">, DUP_UPDATE <span class="token punctuation">}<span class="token punctuation">; </span></span></span></span></span></span></code></pre> </div> <ul> <li>DUP_ERROR:这个代表的就是普通的insert/insert ignore语句<br> 这是我们普通的操作,如果是insert操作则进行抛错给客户端,如果是insert ignore操作则不进行报错,仅仅做一个警告,如下:</li> </ul> <div class="_2Uzcx_"> <button class="VJbwyy" type="button"></button> <pre class="line-numbers language-csharp"><code class=" language-csharp"> <span class="token comment">/* If IGNORE option is used, handler errors will be downgraded to warnings and don't have to stop the iteration. */ mysql<span class="token operator">&gt; insert ignore <span class="token keyword">into tpk2 <span class="token function">values<span class="token punctuation">(<span class="token number">5<span class="token punctuation">,<span class="token string">'g'<span class="token punctuation">,<span class="token string">'m'<span class="token punctuation">)<span class="token punctuation">; <span class="token class-name">Query OK<span class="token punctuation">, <span class="token number">0 rows affected<span class="token punctuation">, <span class="token number">1 warning <span class="token punctuation">(<span class="token number">6 min <span class="token number">3.60 sec<span class="token punctuation">) mysql<span class="token operator">&gt; show warnings <span class="token operator">-&gt; <span class="token punctuation">; <span class="token operator">+<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">-<span class="token operator">+<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">+<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">-<span class="token operator">+ <span class="token operator">| Level <span class="token operator">| Code <span class="token operator">| Message <span class="token operator">| <span class="token operator">+<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">-<span class="token operator">+<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">+<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">-<span class="token operator">+ <span class="token operator">| Warning <span class="token operator">| <span class="token number">1062 <span class="token operator">| <span class="token class-name">Duplicate entry <span class="token string">'5' <span class="token keyword">for key <span class="token string">'PRIMARY' <span class="token operator">| <span class="token operator">+<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">-<span class="token operator">+<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">+<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">--<span class="token operator">-<span class="token operator">+ <span class="token number">1 row <span class="token keyword">in <span class="token keyword">set <span class="token punctuation">(<span class="token number">0.00 sec<span class="token punctuation">) </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre> </div> <p>但是需要注意的是,当前版本报错后,自增值并不会回退。</p> <ul> <li>DUP_REPLACE:这里代表的是replace操作,也就是使用新的插入数据完全代替违反唯一性约束的行数据。我们通常理解的replace是delete/insert的结合,但是实际上并不完全是这样,抛开外键触发器等因素,如果违反的唯一性是最后一个检查的唯一索引的时候,还是会使用update代替,其他情况下就是delete/insert的结合了。如下我们可以看看:</li> </ul> <div class="_2Uzcx_"> <button class="VJbwyy" type="button"></button> <pre class="line-numbers language-php"><code class=" language-php"><span class="token keyword">if <span class="token punctuation">(<span class="token function">last_uniq_key<span class="token punctuation">(table<span class="token punctuation">,key_nr<span class="token punctuation">) <span class="token operator">&amp;&amp;<span class="token comment">//是否是检测的最后一个唯一索引 <span class="token operator">!table<span class="token operator">-<span class="token operator">&gt;<span class="token property">file<span class="token operator">-<span class="token operator">&gt;<span class="token function">referenced_by_foreign_key<span class="token punctuation">(<span class="token punctuation">) <span class="token operator">&amp;&amp; <span class="token punctuation">(<span class="token operator">!table<span class="token operator">-<span class="token operator">&gt;<span class="token property">triggers <span class="token operator">|| <span class="token operator">!table<span class="token operator">-<span class="token operator">&gt;<span class="token property">triggers<span class="token operator">-<span class="token operator">&gt;<span class="token function">has_delete_triggers<span class="token punctuation">(<span class="token punctuation">)<span class="token punctuation">)<span class="token punctuation">) <span class="token punctuation">{ <span class="token keyword">if <span class="token punctuation">(<span class="token punctuation">(error<span class="token operator">=table<span class="token operator">-<span class="token operator">&gt;<span class="token property">file<span class="token operator">-<span class="token operator">&gt;<span class="token function">ha_update_row<span class="token punctuation">(table<span class="token operator">-<span class="token operator">&gt;<span class="token property">record<span class="token punctuation">[<span class="token number">1<span class="token punctuation">]<span class="token punctuation">, table<span class="token operator">-<span class="token operator">&gt;<span class="token property">record<span class="token punctuation">[<span class="token number">0<span class="token punctuation">]<span class="token punctuation">)<span class="token punctuation">) <span class="token operator">&amp;&amp; <span class="token comment">//调用了是update接口 error <span class="token operator">!= <span class="token constant">HA_ERR_RECORD_IS_THE_SAME<span class="token punctuation">) <span class="token keyword">if <span class="token punctuation">(error <span class="token operator">!= <span class="token constant">HA_ERR_RECORD_IS_THE_SAME<span class="token punctuation">) info<span class="token operator">-<span class="token operator">&gt;<span class="token property">stats<span class="token punctuation">.deleted<span class="token operator">++<span class="token punctuation">; <span class="token comment">//影响行数+1 <span class="token keyword">goto after_trg_n_copied_inc<span class="token punctuation">; <span class="token punctuation">} <span class="token keyword">else <span class="token punctuation">{ <span class="token punctuation">.<span class="token punctuation">.<span class="token punctuation">. <span class="token keyword">if <span class="token punctuation">(<span class="token punctuation">(error<span class="token operator">=table<span class="token operator">-<span class="token operator">&gt;<span class="token property">file<span class="token operator">-<span class="token operator">&gt;<span class="token function">ha_delete_row<span class="token punctuation">(table<span class="token operator">-<span class="token operator">&gt;<span class="token property">record<span class="token punctuation">[<span class="token number">1<span class="token punctuation">]<span class="token punctuation">)<span class="token punctuation">)<span class="token punctuation">)<span class="token comment">//删除接口 delete <span class="token keyword">goto err<span class="token punctuation">; info<span class="token operator">-<span class="token operator">&gt;<span class="token property">stats<span class="token punctuation">.deleted<span class="token operator">++<span class="token punctuation">; <span class="token comment">//影响行数+1 <span class="token punctuation">.<span class="token punctuation">.<span class="token punctuation">. <span class="token comment">/* Let us attempt do write_row() once more */<span class="token comment">//这里会进行一次循环进行普通的insert操作 <span class="token punctuation">} </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre> </div> <ul> <li>DUP_UPDATE:这个代表我们的语法insert into on dup,这里就完全等待于update语句了。需要注意的是,这里不是完全替代,会使用语句中的update进行字段的更新,其他字段并不会更新,如下:</li> </ul> <div class="_2Uzcx_"> <button class="VJbwyy" type="button"></button> <pre class="line-numbers language-php"><code class=" language-php"> <span class="token keyword">if <span class="token punctuation">(<span class="token punctuation">(error<span class="token operator">=table<span class="token operator">-<span class="token operator">&gt;<span class="token property">file<span class="token operator">-<span class="token operator">&gt;<span class="token function">ha_update_row<span class="token punctuation">(table<span class="token operator">-<span class="token operator">&gt;<span class="token property">record<span class="token punctuation">[<span class="token number">1<span class="token punctuation">]<span class="token punctuation">, table<span class="token operator">-<span class="token operator">&gt;<span class="token property">record<span class="token punctuation">[<span class="token number">0<span class="token punctuation">]<span class="token punctuation">)<span class="token punctuation">) <span class="token operator">&amp;&amp; <span class="token comment">//调入update接口 error <span class="token operator">!= <span class="token constant">HA_ERR_RECORD_IS_THE_SAME<span class="token punctuation">) <span class="token punctuation">{ <span class="token punctuation">.<span class="token punctuation">.<span class="token punctuation">. <span class="token keyword">if <span class="token punctuation">(error <span class="token operator">!= <span class="token constant">HA_ERR_RECORD_IS_THE_SAME<span class="token punctuation">) info<span class="token operator">-<span class="token operator">&gt;<span class="token property">stats<span class="token punctuation">.updated<span class="token operator">++<span class="token punctuation">;<span class="token comment">//影响行数+1 <span class="token keyword">else error<span class="token operator">= <span class="token number">0<span class="token punctuation">; </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre> </div> <p>再说对于普通的insert操作而言,影响的行数通常为1。replace/insert into on dup如果遇到了<strong>重复行更改后</strong>(注意不是直接插入成功的状态),通常返回影响的行数为2如下:</p> <div class="_2Uzcx_"> <button class="VJbwyy" type="button"></button> <pre class="line-numbers language-csharp"><code class=" language-csharp">mysql<span class="token operator">&gt; replace <span class="token function">testpri2<span class="token punctuation">(id<span class="token punctuation">,a<span class="token punctuation">,b<span class="token punctuation">) <span class="token function">values<span class="token punctuation">(<span class="token number">7<span class="token punctuation">,<span class="token string">'b'<span class="token punctuation">,<span class="token string">'k'<span class="token punctuation">)<span class="token punctuation">; <span class="token class-name">Query OK<span class="token punctuation">, <span class="token number">2 rows affected <span class="token punctuation">(<span class="token number">2.74 sec<span class="token punctuation">) mysql<span class="token operator">&gt; insert <span class="token keyword">into <span class="token function">testpri2<span class="token punctuation">(a<span class="token punctuation">,b<span class="token punctuation">) <span class="token function">values<span class="token punctuation">(<span class="token string">'mmmmnb'<span class="token punctuation">,<span class="token string">'ffhhh'<span class="token punctuation">) on <span class="token class-name">DUPLICATE <span class="token class-name">KEY <span class="token class-name">UPDATE b<span class="token operator">=<span class="token string">'bj'<span class="token punctuation">; <span class="token class-name">Query OK<span class="token punctuation">, <span class="token number">2 rows affected <span class="token punctuation">(<span class="token number">3.81 sec<span class="token punctuation">) </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre> </div> <ul> <li>replace:如果是调用update接口则,不会真正执行insert操作,会在info-&gt;stats.deleted++进行影响行数+1,最后在insert接口中还会+1。如果是调用delete/insert操作会真正执行insert操作,正常的info-&gt;stats.deleted++进行+1操作,最后在insert接口中还会+1。因此它们结果还是2。</li> <li>insert into on dup:肯定调用update接口,不会真正执行insert操作,会在 info-&gt;stats.updated++;进行影响行数+1,然后会直接进行info-&gt;stats.copied++进行影响行数+1,因此为2。</li> </ul> <p>因此不管怎么看起来都是影响行数为2,也不要奇怪。</p> <h3>其他:</h3> <p>DML回执接口:</p> <div class="_2Uzcx_"> <button class="VJbwyy" type="button"></button> <div class="cnblogs_code"> <pre>#<span style="color: rgba(128, 0, 0, 1); font-weight: bold">0</span> my_ok (thd<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x6ddc080</span>, affected_rows<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">1</span>, id<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0</span>, message<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x7fffec4357d0</span> "Rows matched: <span style="color: rgba(128, 0, 0, 1); font-weight: bold">1</span> Changed: <span style="color: rgba(128, 0, 0, 1); font-weight: bold">1</span> Warnings: <span style="color: rgba(128, 0, 0, 1); font-weight: bold">0</span>") at <span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">-</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">5.7</span>.<span style="color: rgba(128, 0, 0, 1); font-weight: bold">26</span><span style="color: rgba(128, 128, 128, 1)">/</span>sql<span style="color: rgba(128, 128, 128, 1)">/</span>sql_class.h:<span style="color: rgba(128, 0, 0, 1); font-weight: bold">4753</span><span style="color: rgba(0, 0, 0, 1)"> #</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">1</span> <span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x0000000001652574</span> <span style="color: rgba(128, 128, 128, 1)">in</span> mysql_update (thd<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x6ddc080</span>, fields<span style="color: rgba(128, 128, 128, 1)">=</span>..., <span style="color: rgba(0, 0, 255, 1)">values</span><span style="color: rgba(128, 128, 128, 1)">=</span>..., limit<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">18446744073709551614</span>, handle_duplicates<span style="color: rgba(128, 128, 128, 1)">=</span>DUP_ERROR, found_return<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x7fffec435d28</span><span style="color: rgba(0, 0, 0, 1)">, updated_return</span><span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x7fffec435d20</span>) at <span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">-</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">5.7</span>.<span style="color: rgba(128, 0, 0, 1); font-weight: bold">26</span><span style="color: rgba(128, 128, 128, 1)">/</span>sql<span style="color: rgba(128, 128, 128, 1)">/</span>sql_update.cc:<span style="color: rgba(128, 0, 0, 1); font-weight: bold">1092</span><span style="color: rgba(0, 0, 0, 1)"> #</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">2</span> <span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x00000000016580ea</span> <span style="color: rgba(128, 128, 128, 1)">in</span> Sql_cmd_update::try_single_table_update (this<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x6df2350</span>, thd<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x6ddc080</span>, switch_to_multitable<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x7fffec435dcf</span><span style="color: rgba(0, 0, 0, 1)">) at </span><span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">-</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">5.7</span>.<span style="color: rgba(128, 0, 0, 1); font-weight: bold">26</span><span style="color: rgba(128, 128, 128, 1)">/</span>sql<span style="color: rgba(128, 128, 128, 1)">/</span>sql_update.cc:<span style="color: rgba(128, 0, 0, 1); font-weight: bold">2891</span><span style="color: rgba(0, 0, 0, 1)"> #</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">3</span> <span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x0000000001658637</span> <span style="color: rgba(128, 128, 128, 1)">in</span> Sql_cmd_update::<span style="color: rgba(0, 0, 255, 1)">execute</span> (this<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x6df2350</span>, thd<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x6ddc080</span>) at <span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">-</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">5.7</span>.<span style="color: rgba(128, 0, 0, 1); font-weight: bold">26</span><span style="color: rgba(128, 128, 128, 1)">/</span>sql<span style="color: rgba(128, 128, 128, 1)">/</span>sql_update.cc:<span style="color: rgba(128, 0, 0, 1); font-weight: bold">3018</span><span style="color: rgba(0, 0, 0, 1)"> #</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">4</span> <span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x000000000159a7ba</span> <span style="color: rgba(128, 128, 128, 1)">in</span> mysql_execute_command (thd<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x6ddc080</span>, first_level<span style="color: rgba(128, 128, 128, 1)">=</span>true) at <span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">-</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">5.7</span>.<span style="color: rgba(128, 0, 0, 1); font-weight: bold">26</span><span style="color: rgba(128, 128, 128, 1)">/</span>sql<span style="color: rgba(128, 128, 128, 1)">/</span>sql_parse.cc:<span style="color: rgba(128, 0, 0, 1); font-weight: bold">3606</span><span style="color: rgba(0, 0, 0, 1)"> #</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">5</span> <span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x00000000015a06c0</span> <span style="color: rgba(128, 128, 128, 1)">in</span> mysql_parse (thd<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x6ddc080</span>, parser_state<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x7fffec437610</span>) at <span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">-</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">5.7</span>.<span style="color: rgba(128, 0, 0, 1); font-weight: bold">26</span><span style="color: rgba(128, 128, 128, 1)">/</span>sql<span style="color: rgba(128, 128, 128, 1)">/</span>sql_parse.cc:<span style="color: rgba(128, 0, 0, 1); font-weight: bold">5570</span><span style="color: rgba(0, 0, 0, 1)"> #</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">6</span> <span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x0000000001595283</span> <span style="color: rgba(128, 128, 128, 1)">in</span> dispatch_command (thd<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x6ddc080</span>, com_data<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x7fffec437d80</span>, command<span style="color: rgba(128, 128, 128, 1)">=</span>COM_QUERY) at <span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">-</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">5.7</span>.<span style="color: rgba(128, 0, 0, 1); font-weight: bold">26</span><span style="color: rgba(128, 128, 128, 1)">/</span>sql<span style="color: rgba(128, 128, 128, 1)">/</span>sql_parse.cc:<span style="color: rgba(128, 0, 0, 1); font-weight: bold">1484</span><span style="color: rgba(0, 0, 0, 1)"> #</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">7</span> <span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x00000000015940bc</span> <span style="color: rgba(128, 128, 128, 1)">in</span> do_command (thd<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x6ddc080</span>) at <span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">-</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">5.7</span>.<span style="color: rgba(128, 0, 0, 1); font-weight: bold">26</span><span style="color: rgba(128, 128, 128, 1)">/</span>sql<span style="color: rgba(128, 128, 128, 1)">/</span>sql_parse.cc:<span style="color: rgba(128, 0, 0, 1); font-weight: bold">1025</span><span style="color: rgba(0, 0, 0, 1)"> #</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">8</span> <span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x00000000016cbf91</span> <span style="color: rgba(128, 128, 128, 1)">in</span> handle_connection (arg<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x6dd9480</span>) at <span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">-</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">5.7</span>.<span style="color: rgba(128, 0, 0, 1); font-weight: bold">26</span><span style="color: rgba(128, 128, 128, 1)">/</span>sql<span style="color: rgba(128, 128, 128, 1)">/</span>conn_handler<span style="color: rgba(128, 128, 128, 1)">/</span>connection_handler_per_thread.cc:<span style="color: rgba(128, 0, 0, 1); font-weight: bold">306</span><span style="color: rgba(0, 0, 0, 1)"> #</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">9</span> <span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x0000000001921c64</span> <span style="color: rgba(128, 128, 128, 1)">in</span> pfs_spawn_thread (arg<span style="color: rgba(128, 128, 128, 1)">=</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x6da4430</span>) at <span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">/</span>mysql<span style="color: rgba(128, 128, 128, 1)">-</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">5.7</span>.<span style="color: rgba(128, 0, 0, 1); font-weight: bold">26</span><span style="color: rgba(128, 128, 128, 1)">/</span>storage<span style="color: rgba(128, 128, 128, 1)">/</span>perfschema<span style="color: rgba(128, 128, 128, 1)">/</span>pfs.cc:<span style="color: rgba(128, 0, 0, 1); font-weight: bold">2190</span><span style="color: rgba(0, 0, 0, 1)"> #</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">10</span> <span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x0000003823e079d1</span> <span style="color: rgba(128, 128, 128, 1)">in</span> start_thread () <span style="color: rgba(0, 0, 255, 1)">from</span> <span style="color: rgba(128, 128, 128, 1)">/</span>lib64<span style="color: rgba(128, 128, 128, 1)">/</span>libpthread.so.<span style="color: rgba(128, 0, 0, 1); font-weight: bold">0</span><span style="color: rgba(0, 0, 0, 1)"> #</span><span style="color: rgba(128, 0, 0, 1); font-weight: bold">11</span> <span style="color: rgba(128, 0, 0, 1); font-weight: bold">0x0000003823ae8b6d</span> <span style="color: rgba(128, 128, 128, 1)">in</span> clone () <span style="color: rgba(0, 0, 255, 1)">from</span> <span style="color: rgba(128, 128, 128, 1)">/</span>lib64<span style="color: rgba(128, 128, 128, 1)">/</span>libc.so.<span style="color: rgba(128, 0, 0, 1); font-weight: bold">6</span></pre> </div> <p>&nbsp;</p> </div> </div> <br> <br> <br> </div> </div> <p><img src="https://uploadfiles.nowcoder.com/images/20211012/7200794_1634014642232_D0BC3A2BF262FD12D8E559F366F686D3"></p> <p>&nbsp;</p> <p>&nbsp;</p> <p><span style="white-space: nowrap; font-family: Microsoft YaHei; font-size: 18px">MySQL修改大表工具pt-online-schema-change的使用限制:</span></p> <p><span style="white-space: nowrap; font-family: Microsoft YaHei; font-size: 18px"> 1)、如果修改表有外键,除非使用 --alter-foreign-keys-method 指定特定的值,否则工具不予执行</span></p> <p><span style="white-space: nowrap; font-family: Microsoft YaHei; font-size: 18px"> 2)、被修改表必须要有主键,否则报错:Cannot chunk the original table `houyi`.`ga`: There is no good index and the table is oversized. at ./pt-online-schema-change line 5353.</span></p> <p><span style="white-space: nowrap; font-family: Microsoft YaHei; font-size: 18px"> 3)、被修改表上不能有针对after delete|insert|update三个触发器,否则修改表结构操作失败</span></p> <p><span style="white-space: nowrap; font-family: Microsoft YaHei; font-size: 18px"> MySQL修改大表工具pt-online-schema-change原理:</span></p> <p><span style="white-space: nowrap; font-family: Microsoft YaHei; font-size: 18px"> 1)、首先使用帐号密码连接到mysql后,获取指定表的状态信息,检查是否有触发器,检查表是否有主键。</span></p> <p><span style="white-space: nowrap; font-family: Microsoft YaHei; font-size: 18px"> 2)、接着按照修改表的表定义,新建一个名为'_tb_new'不可见的临时表,对这个表执行alter添加字段,并校验是否执行成功。</span></p> <p><span style="white-space: nowrap; font-family: Microsoft YaHei; font-size: 18px"> 3)、然后针对源表创建三个触发器,分别如下:</span></p> <p><span style="white-space: nowrap; font-family: Microsoft YaHei; font-size: 18px"> create trigger db_tb_del after delete on db.tb for each row delete ignore from db._tb_new where db._tb_new.id &lt;=&gt; OLD.id #删掉新表中db._tb_new.id &lt;=&gt; OLD.id的数据,否则忽略操作</span></p> <p><span style="white-space: nowrap; font-family: Microsoft YaHei; font-size: 18px"> create trigger db_tb_del after update on db.tb for each row replace into db._tb_new(id,...) values(new.id,...)&nbsp; #源表执行update的时候,把对应的数据replace into的方式写入新表</span></p> <p><span style="white-space: nowrap; font-family: Microsoft YaHei; font-size: 18px"> create trigger db_tb_del after insert on db.tb for each row replace into db._tb_new(id,...) values(new.id,...)&nbsp; #源表执行insert操作的时候,把对应的数据replace into的方式写入新表</span></p> <p><span style="white-space: nowrap; font-family: Microsoft YaHei; font-size: 18px"> 4)、触发器创建好之后会执行insert low_priority ignore into db._tb_new(id,..) select id,... from tb lock in share mode语句复制源表数据到新表。</span></p> <p><span style="white-space: nowrap; font-family: Microsoft YaHei; font-size: 18px"> 5)、复制完成之后执行语句:rename table db.tb to db._tb_old,db._tb_new to db.tb同时把源表修改为_tb_old格式,把新表_tb_new修改为源表名字的原子修改。</span></p> <p><span style="white-space: nowrap; font-family: Microsoft YaHei; font-size: 18px"> 6)、接着,如果没有加不删除old表的选项,那么就会删除Old表,然后删除三个触发器。到这里就完成了在线表结构的修改 。整个过程只在rename表的时间会锁一下表,其他时候不锁表。</span></p> <p>&nbsp;</p>