Skip to content

Commit 7e6b233

Browse files
committed
Force migration key for composite chunk boundaries
1 parent 9725ea9 commit 7e6b233

3 files changed

Lines changed: 34 additions & 32 deletions

File tree

go/logic/applier.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,7 @@ func (apl *Applier) CalculateNextIterationRangeEndValues() (hasFurtherRange bool
11061106
query, explodedArgs, err := buildFunc(
11071107
apl.migrationContext.DatabaseName,
11081108
apl.migrationContext.OriginalTableName,
1109+
apl.migrationContext.UniqueKey.Name,
11091110
&apl.migrationContext.UniqueKey.Columns,
11101111
apl.migrationContext.MigrationIterationRangeMinValues.AbstractValues(),
11111112
apl.migrationContext.MigrationRangeMaxValues.AbstractValues(),

go/sql/builder.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ func BuildRangeInsertPreparedQuery(databaseName, originalTableName, ghostTableNa
425425
return BuildRangeInsertQuery(databaseName, originalTableName, ghostTableName, sharedColumns, mappedSharedColumns, uniqueKey, uniqueKeyColumns, rangeStartValues, rangeEndValues, rangeStartArgs, rangeEndArgs, includeRangeStartValues, transactionalTable, noWait)
426426
}
427427

428-
func BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, tableName string, uniqueKeyColumns *ColumnList, rangeStartArgs, rangeEndArgs []interface{}, chunkSize int64, includeRangeStartValues bool, hint string) (result string, explodedArgs []interface{}, err error) {
428+
func BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, tableName, uniqueKey string, uniqueKeyColumns *ColumnList, rangeStartArgs, rangeEndArgs []interface{}, chunkSize int64, includeRangeStartValues bool, hint string) (result string, explodedArgs []interface{}, err error) {
429429
if uniqueKeyColumns.Len() == 0 {
430430
return "", explodedArgs, fmt.Errorf("got 0 columns in BuildUniqueKeyRangeEndPreparedQuery")
431431
}
@@ -438,7 +438,7 @@ func BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, tableName string
438438
}
439439

440440
if uniqueKeyColumns.Len() == 2 {
441-
return buildUniqueKeyRangeEndTwoColumnViaOffset(databaseName, tableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, startRangeComparisonSign, hint)
441+
return buildUniqueKeyRangeEndTwoColumnViaOffset(databaseName, tableName, EscapeName(uniqueKey), uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, startRangeComparisonSign, hint)
442442
}
443443

444444
rangeStartComparison, rangeExplodedArgs, err := BuildRangePreparedComparison(uniqueKeyColumns, rangeStartArgs, startRangeComparisonSign)
@@ -483,7 +483,7 @@ func BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, tableName string
483483
return result, explodedArgs, nil
484484
}
485485

486-
func BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, tableName string, uniqueKeyColumns *ColumnList, rangeStartArgs, rangeEndArgs []interface{}, chunkSize int64, includeRangeStartValues bool, hint string) (result string, explodedArgs []interface{}, err error) {
486+
func BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, tableName, uniqueKey string, uniqueKeyColumns *ColumnList, rangeStartArgs, rangeEndArgs []interface{}, chunkSize int64, includeRangeStartValues bool, hint string) (result string, explodedArgs []interface{}, err error) {
487487
if uniqueKeyColumns.Len() == 0 {
488488
return "", explodedArgs, fmt.Errorf("got 0 columns in BuildUniqueKeyRangeEndPreparedQuery")
489489
}
@@ -496,7 +496,7 @@ func BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, tableName str
496496
}
497497

498498
if uniqueKeyColumns.Len() == 2 {
499-
return buildUniqueKeyRangeEndTwoColumnViaTemptable(databaseName, tableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, startRangeComparisonSign, hint)
499+
return buildUniqueKeyRangeEndTwoColumnViaTemptable(databaseName, tableName, EscapeName(uniqueKey), uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, startRangeComparisonSign, hint)
500500
}
501501

502502
rangeStartComparison, rangeExplodedArgs, err := BuildRangePreparedComparison(uniqueKeyColumns, rangeStartArgs, startRangeComparisonSign)
@@ -616,7 +616,7 @@ func buildTwoColumnUnionParts(
616616
}
617617

618618
func buildUniqueKeyRangeEndTwoColumnViaOffset(
619-
databaseName, tableName string,
619+
databaseName, tableName, uniqueKey string,
620620
uniqueKeyColumns *ColumnList,
621621
rangeStartArgs, rangeEndArgs []interface{},
622622
chunkSize int64,
@@ -629,15 +629,15 @@ func buildUniqueKeyRangeEndTwoColumnViaOffset(
629629
}
630630
col2StartOp := string(startRangeComparisonSign)
631631
selectClause := m.col1Name + ", " + m.col2Name
632-
fromClause := databaseName + "." + tableName
632+
fromClause := fmt.Sprintf("%s.%s force index (%s)", databaseName, tableName, uniqueKey)
633633
partSuffix := fmt.Sprintf("order by %s limit %d", m.orderByAsc, chunkSize)
634634

635635
if sameFirstColumnValue(rangeStartArgs, rangeEndArgs) {
636636
result = fmt.Sprintf(`
637637
select /* gh-ost %s.%s %s */
638638
%s, %s
639639
from
640-
%s.%s
640+
%s
641641
where
642642
(%s = %s and %s %s %s and %s <= %s)
643643
order by
@@ -646,7 +646,7 @@ func buildUniqueKeyRangeEndTwoColumnViaOffset(
646646
offset %d`,
647647
databaseName, tableName, hint,
648648
m.col1Name, m.col2Name,
649-
databaseName, tableName,
649+
fromClause,
650650
m.col1Name, m.col1Val, m.col2Name, col2StartOp, m.col2Val, m.col2Name, m.col2Val,
651651
m.orderByAsc,
652652
chunkSize-1,
@@ -682,7 +682,7 @@ func buildUniqueKeyRangeEndTwoColumnViaOffset(
682682
}
683683

684684
func buildUniqueKeyRangeEndTwoColumnViaTemptable(
685-
databaseName, tableName string,
685+
databaseName, tableName, uniqueKey string,
686686
uniqueKeyColumns *ColumnList,
687687
rangeStartArgs, rangeEndArgs []interface{},
688688
chunkSize int64,
@@ -695,15 +695,15 @@ func buildUniqueKeyRangeEndTwoColumnViaTemptable(
695695
}
696696
col2StartOp := string(startRangeComparisonSign)
697697
selectClause := m.col1Name + ", " + m.col2Name
698-
fromClause := databaseName + "." + tableName
698+
fromClause := fmt.Sprintf("%s.%s force index (%s)", databaseName, tableName, uniqueKey)
699699
partSuffix := fmt.Sprintf("order by %s limit %d", m.orderByAsc, chunkSize)
700700

701701
if sameFirstColumnValue(rangeStartArgs, rangeEndArgs) {
702702
result = fmt.Sprintf(`
703703
select /* gh-ost %s.%s %s */ %s, %s
704704
from (
705705
select %s, %s
706-
from %s.%s
706+
from %s
707707
where (%s = %s and %s %s %s and %s <= %s)
708708
order by %s
709709
limit %d
@@ -712,7 +712,7 @@ func buildUniqueKeyRangeEndTwoColumnViaTemptable(
712712
limit 1`,
713713
databaseName, tableName, hint, m.col1Name, m.col2Name,
714714
m.col1Name, m.col2Name,
715-
databaseName, tableName,
715+
fromClause,
716716
m.col1Name, m.col1Val, m.col2Name, col2StartOp, m.col2Val, m.col2Name, m.col2Val,
717717
m.orderByAsc, chunkSize,
718718
m.orderByDesc,

go/sql/builder_test.go

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -423,21 +423,22 @@ func TestBuildUniqueKeyRangeEndPreparedQueryViaOffset(t *testing.T) {
423423
var chunkSize int64 = 500
424424
{
425425
// Different first-column values → 3-part UNION for efficient boundary seeks.
426+
// A named (non-PRIMARY) key asserts the caller-supplied key reaches the force index hint.
426427
uniqueKeyColumns := NewColumnList([]string{"name", "position"})
427428
rangeStartArgs := []interface{}{3, 17}
428429
rangeEndArgs := []interface{}{103, 117}
429430

430-
query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, originalTableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test")
431+
query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, originalTableName, "name_position_uidx", uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test")
431432
require.NoError(t, err)
432433
expected := `
433434
select /* gh-ost mydb.tbl test */
434435
name, position
435436
from
436-
((select name, position from mydb.tbl where name = ? and position > ? order by name asc, position asc limit 500)
437+
((select name, position from mydb.tbl force index (name_position_uidx) where name = ? and position > ? order by name asc, position asc limit 500)
437438
union all
438-
(select name, position from mydb.tbl where name > ? and name < ? order by name asc, position asc limit 500)
439+
(select name, position from mydb.tbl force index (name_position_uidx) where name > ? and name < ? order by name asc, position asc limit 500)
439440
union all
440-
(select name, position from mydb.tbl where name = ? and position <= ? order by name asc, position asc limit 500)) t
441+
(select name, position from mydb.tbl force index (name_position_uidx) where name = ? and position <= ? order by name asc, position asc limit 500)) t
441442
order by
442443
name asc, position asc
443444
limit 1
@@ -451,13 +452,13 @@ func TestBuildUniqueKeyRangeEndPreparedQueryViaOffset(t *testing.T) {
451452
rangeStartArgs := []interface{}{3, 17}
452453
rangeEndArgs := []interface{}{3, 117}
453454

454-
query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, originalTableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test")
455+
query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, originalTableName, "PRIMARY", uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test")
455456
require.NoError(t, err)
456457
expected := `
457458
select /* gh-ost mydb.tbl test */
458459
name, position
459460
from
460-
mydb.tbl
461+
mydb.tbl force index (PRIMARY)
461462
where
462463
(name = ? and position > ? and position <= ?)
463464
order by
@@ -479,18 +480,18 @@ func TestBuildUniqueKeyRangeEndPreparedQueryViaTemptable(t *testing.T) {
479480
rangeStartArgs := []interface{}{3, 17}
480481
rangeEndArgs := []interface{}{103, 117}
481482

482-
query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, originalTableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test")
483+
query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, originalTableName, "PRIMARY", uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test")
483484
require.NoError(t, err)
484485
expected := `
485486
select /* gh-ost mydb.tbl test */ name, position
486487
from (
487488
select name, position
488489
from
489-
((select name, position from mydb.tbl where name = ? and position > ? order by name asc, position asc limit 500)
490+
((select name, position from mydb.tbl force index (PRIMARY) where name = ? and position > ? order by name asc, position asc limit 500)
490491
union all
491-
(select name, position from mydb.tbl where name > ? and name < ? order by name asc, position asc limit 500)
492+
(select name, position from mydb.tbl force index (PRIMARY) where name > ? and name < ? order by name asc, position asc limit 500)
492493
union all
493-
(select name, position from mydb.tbl where name = ? and position <= ? order by name asc, position asc limit 500)) t
494+
(select name, position from mydb.tbl force index (PRIMARY) where name = ? and position <= ? order by name asc, position asc limit 500)) t
494495
order by name asc, position asc
495496
limit 500
496497
) select_osc_chunk
@@ -505,13 +506,13 @@ func TestBuildUniqueKeyRangeEndPreparedQueryViaTemptable(t *testing.T) {
505506
rangeStartArgs := []interface{}{3, 17}
506507
rangeEndArgs := []interface{}{3, 117}
507508

508-
query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, originalTableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test")
509+
query, explodedArgs, err := BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, originalTableName, "PRIMARY", uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test")
509510
require.NoError(t, err)
510511
expected := `
511512
select /* gh-ost mydb.tbl test */ name, position
512513
from (
513514
select name, position
514-
from mydb.tbl
515+
from mydb.tbl force index (PRIMARY)
515516
where (name = ? and position > ? and position <= ?)
516517
order by name asc, position asc
517518
limit 500
@@ -535,17 +536,17 @@ func TestBuildUniqueKeyRangeEndPreparedQueryTwoColumnEnum(t *testing.T) {
535536
rangeStartArgs := []interface{}{"a", 17}
536537
rangeEndArgs := []interface{}{"z", 117}
537538

538-
query, _, err := BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, originalTableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test")
539+
query, _, err := BuildUniqueKeyRangeEndPreparedQueryViaOffset(databaseName, originalTableName, "PRIMARY", uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test")
539540
require.NoError(t, err)
540541
expected := `
541542
select /* gh-ost mydb.tbl test */
542543
name, position
543544
from
544-
((select name, position from mydb.tbl where name = ? and position > ? order by concat(name) asc, position asc limit 500)
545+
((select name, position from mydb.tbl force index (PRIMARY) where name = ? and position > ? order by concat(name) asc, position asc limit 500)
545546
union all
546-
(select name, position from mydb.tbl where name > ? and name < ? order by concat(name) asc, position asc limit 500)
547+
(select name, position from mydb.tbl force index (PRIMARY) where name > ? and name < ? order by concat(name) asc, position asc limit 500)
547548
union all
548-
(select name, position from mydb.tbl where name = ? and position <= ? order by concat(name) asc, position asc limit 500)) t
549+
(select name, position from mydb.tbl force index (PRIMARY) where name = ? and position <= ? order by concat(name) asc, position asc limit 500)) t
549550
order by
550551
concat(name) asc, position asc
551552
limit 1
@@ -560,18 +561,18 @@ func TestBuildUniqueKeyRangeEndPreparedQueryTwoColumnEnum(t *testing.T) {
560561
rangeStartArgs := []interface{}{3, "a"}
561562
rangeEndArgs := []interface{}{103, "z"}
562563

563-
query, _, err := BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, originalTableName, uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test")
564+
query, _, err := BuildUniqueKeyRangeEndPreparedQueryViaTemptable(databaseName, originalTableName, "PRIMARY", uniqueKeyColumns, rangeStartArgs, rangeEndArgs, chunkSize, false, "test")
564565
require.NoError(t, err)
565566
expected := `
566567
select /* gh-ost mydb.tbl test */ name, position
567568
from (
568569
select name, position
569570
from
570-
((select name, position from mydb.tbl where name = ? and position > ? order by name asc, concat(position) asc limit 500)
571+
((select name, position from mydb.tbl force index (PRIMARY) where name = ? and position > ? order by name asc, concat(position) asc limit 500)
571572
union all
572-
(select name, position from mydb.tbl where name > ? and name < ? order by name asc, concat(position) asc limit 500)
573+
(select name, position from mydb.tbl force index (PRIMARY) where name > ? and name < ? order by name asc, concat(position) asc limit 500)
573574
union all
574-
(select name, position from mydb.tbl where name = ? and position <= ? order by name asc, concat(position) asc limit 500)) t
575+
(select name, position from mydb.tbl force index (PRIMARY) where name = ? and position <= ? order by name asc, concat(position) asc limit 500)) t
575576
order by name asc, concat(position) asc
576577
limit 500
577578
) select_osc_chunk

0 commit comments

Comments
 (0)