Comment 10 for bug 918056

Revision history for this message
Daniel Nichter (daniel-nichter) wrote : Re: pt-table-sync can't nibble table because MySQL chose no index

I found the problem. First, the differing chunk is what we can an "oob" (out-of-bounds) chunk:

master:
*************************** 3. row ***************************
            db: test
           tbl: history
         chunk: 3
    chunk_time: 0.000658
   chunk_index: PRIMARY
lower_boundary: NULL
upper_boundary: 21,21,1045
      this_crc: 0
      this_cnt: 0
    master_crc: 0
    master_cnt: 0
            ts: 2013-01-23 08:00:17

slave:
*************************** 3. row ***************************
            db: test
           tbl: history
         chunk: 3
    chunk_time: 0.000658
   chunk_index: PRIMARY
lower_boundary: NULL
upper_boundary: 21,21,1045
      this_crc: 0
      this_cnt: 49
    master_crc: 0
    master_cnt: 0
            ts: 2013-01-23 08:00:17

this_cnt differe, and notice that lower_boundary=NULL: this (or upper_boundary=NULL) signal an oob chunk. When lower_boundary=NULL it's pt-table-checksum's chunk WHERE index_cols < first_row. The reason for that is precisely this test case:

master has row 5,6,7,8
slave has rows 1,2,3,4,5,6,7,8

So doing WHERE rows < 5 on master will detect the out-of-sync rows 1,2,3,4 on the slave.

Problem is, pt-table-checksum and pt-table-sync use different chunking methods. We make them compatible by converting ptc boundaries to pts boundaries in sub diff_where(), but that sub is not currently handling oob chunks correctly, resulting in a chunk like:

SELECT /*nibble boundary 0*/ `uid`,`nid`,`timestamp` FROM `test`.`history` FORCE INDEX (`PRIMARY`) WHERE (((`uid` > NULL) OR (`uid` = NULL AND `nid` >= NULL)) AND ((`uid` < '21') OR (`uid` = '21' AND `nid` <= '1045'))) ORDER BY `uid`,`nid` LIMIT 999, 1

which is an impossible WHERE clause, hence MySQL chooses no index.

So the fix is making diff_where() handle oob chunks correctly.