Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/.vuepress/sidebar/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ module.exports = [
"alter-table-rollup",
"alter-table-schema-change",
"alter-table-temp-partition",
"alter-table-replace-table",
],
sidebarDepth: 2,
},
Expand Down
1 change: 1 addition & 0 deletions docs/.vuepress/sidebar/zh-CN.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ module.exports = [
"alter-table-rollup",
"alter-table-schema-change",
"alter-table-temp-partition",
"alter-table-replace-table",
],
sidebarDepth: 2,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
{
"title": "Replace Table",
"language": "en"
}
---

<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->

# Replace Table

In version 0.14, Doris supports atomic replacement of two tables.
This operation only applies to OLAP tables.

For partition level replacement operations, please refer to [Temporary Partition Document](./alter-table-temp-partition.md)

## Syntax

```
ALTER TABLE [db.]tbl1 REPLACE WITH tbl2
[PROPERTIES('swap' = 'true')];
```

Replace table `tbl1` with table `tbl2`.

If the `swap` parameter is `true`, after replacement, the data in the table named `tbl1` is the data in the original `tbl2` table. The data in the table named `tbl2` is the data in the original table `tbl1`. That is, the data of the two tables are interchanged.

If the `swap` parameter is `true`, after replacement, the data in the table named `tbl1` is the data in the original `tbl2` table. The table named `tbl2` is dropped.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

false ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


## Principle

The replacement table function actually turns the following set of operations into an atomic operation.

Suppose you want to replace table A with table B, and `swap` is `true`, the operation is as follows:

1. Rename table B to table A.
2. Rename table A to table B.

If `swap` is `true`, the operation is as follows:

1. Drop table A.
2. Rename table B to table A.

## Notice

1. The `swap` parameter defaults to `true`. That is, the replacement table operation is equivalent to the exchange of two table data.
2. If the `swap` parameter is set to `false`, the replaced table (table A) will be dropped and cannot be recovered.
3. The replacement operation can only occur between two OLAP tables, and the table structure of the two tables is not checked for consistency.
4. The replacement operation will not change the original permission settings. Because the permission check is based on the table name.

## Best Practices

1. Atomic Overwrite Operation

In some cases, the user wants to be able to rewrite the data of a certain table, but if it is dropped and then imported, there will be a period of time in which the data cannot be viewed. At this time, the user can first use the `CREATE TABLE LIKE` statement to create a new table with the same structure, import the new data into the new table, and replace the old table atomically through the replacement operation to achieve the goal. For partition level atomic overwrite operation, please refer to [Temporary partition document](./alter-table-temp-partition.md)
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ Users can load data into temporary partitions or specify temporary partitions fo

1. Atomic overwrite

In some cases, the user wants to be able to rewrite the data of a certain partition, but if it is dropped first and then loaded, there will be a period of time when the data cannot be seen. This is, the user can first create a corresponding temporary partition, load new data into the temporary partition, and then replace the original partition atomically through the `REPLACE` operation to achieve the purpose.
In some cases, the user wants to be able to rewrite the data of a certain partition, but if it is dropped first and then loaded, there will be a period of time when the data cannot be seen. At this moment, the user can first create a corresponding temporary partition, load new data into the temporary partition, and then replace the original partition atomically through the `REPLACE` operation to achieve the purpose. For atomic overwrite operations of non-partitioned tables, please refer to [Replace Table Document](./alter-table-replace-table.md)

2. Modify the number of buckets

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
{
"title": "替换表",
"language": "zh-CN"
}
---

<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->

# 替换表

在 0.14 版本中,Doris 支持对两个表进行原子的替换操作。
该操作仅适用于 OLAP 表。

分区级别的替换操作,请参阅 [临时分区文档](./alter-table-temp-partition.md)

## 语法说明

```
ALTER TABLE [db.]tbl1 REPLACE WITH tbl2
[PROPERTIES('swap' = 'true')];
```

将表 tbl1 替换为表 tbl2。

如果 `swap` 参数为 `true`,则替换后,名称为 `tbl1` 表中的数据为原 `tbl2` 表中的数据。而名称为 `tbl2` 表中的数据为原 `tbl1` 表中的数据。即两张表数据发生了互换。

如果 `swap` 参数为 `true`,则替换后,名称为 `tbl1` 表中的数据为原 `tbl2` 表中的数据。而名称为 `tbl2` 表被删除。
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be false ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed



## 原理

替换表功能,实际上是将以下操作集合变成一个原子操作。

假设要将表 A 替换为表 B,且 `swap` 为 `true`,则操作如下:

1. 将表 B 重名为表 A。
2. 将表 A 重名为表 B。

如果 `swap` 为 `true`,则操作如下:

1. 删除表 A。
2. 将表 B 重名为表 A。

## 注意事项

1. `swap` 参数默认为 `true`。即替换表操作相当于将两张表数据进行交换。
2. 如果设置 `swap` 参数为 `false`,则被替换的表(表A)将被删除,且无法恢复。
3. 替换操作仅能发生在两张 OLAP 表之间,且不会检查两张表的表结构是否一致。
4. 替换操作不会改变原有的权限设置。因为权限检查以表名称为准。

## 最佳实践

1. 原子的覆盖写操作

某些情况下,用户希望能够重写某张表的数据,但如果采用先删除再导入的方式进行,在中间会有一段时间无法查看数据。这时,用户可以先使用 `CREATE TABLE LIKE` 语句创建一个相同结构的新表,将新的数据导入到新表后,通过替换操作,原子的替换旧表,以达到目的。分区级别的原子覆盖写操作,请参阅 [临时分区文档](./alter-table-temp-partition.md)
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ PROPERTIES (

1. 原子的覆盖写操作

某些情况下,用户希望能够重写某一分区的数据,但如果采用先删除再导入的方式进行,在中间会有一段时间无法查看数据。这是,用户可以先创建一个对应的临时分区,将新的数据导入到临时分区后,通过替换操作,原子的替换原有分区,以达到目的。
某些情况下,用户希望能够重写某一分区的数据,但如果采用先删除再导入的方式进行,在中间会有一段时间无法查看数据。这时,用户可以先创建一个对应的临时分区,将新的数据导入到临时分区后,通过替换操作,原子的替换原有分区,以达到目的。对于非分区表的原子覆盖写操作,请参阅[替换表文档](./alter-table-replace-table.md)

2. 修改分桶数

Expand Down
4 changes: 4 additions & 0 deletions fe/fe-core/src/main/cup/sql_parser.cup
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,10 @@ alter_table_clause ::=
{:
RESULT = new ReplacePartitionClause(partitions, tempPartitions, properties);
:}
| KW_REPLACE KW_WITH KW_TABLE ident:tblName opt_properties:properties
{:
RESULT = new ReplaceTableClause(tblName, properties);
:}
| KW_RENAME ident:newTableName
{:
RESULT = new TableRenameClause(newTableName);
Expand Down
91 changes: 88 additions & 3 deletions fe/fe-core/src/main/java/org/apache/doris/alter/Alter.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.apache.doris.analysis.ModifyTablePropertiesClause;
import org.apache.doris.analysis.PartitionRenameClause;
import org.apache.doris.analysis.ReplacePartitionClause;
import org.apache.doris.analysis.ReplaceTableClause;
import org.apache.doris.analysis.RollupRenameClause;
import org.apache.doris.analysis.TableName;
import org.apache.doris.analysis.TableRenameClause;
Expand All @@ -55,15 +56,17 @@
import org.apache.doris.persist.AlterViewInfo;
import org.apache.doris.persist.BatchModifyPartitionsInfo;
import org.apache.doris.persist.ModifyPartitionInfo;
import org.apache.doris.persist.ReplaceTableOperationLog;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.thrift.TTabletType;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -233,6 +236,8 @@ public void processAlterTable(AlterTableStmt stmt) throws UserException {
}
} else if (currentAlterOps.hasRenameOp()) {
processRename(db, olapTable, alterClauses);
} else if (currentAlterOps.hasReplaceTableOp()) {
processReplaceTable(db, olapTable, alterClauses);
} else if (currentAlterOps.contains(AlterOpType.MODIFY_TABLE_PROPERTY_SYNC)) {
needProcessOutsideDatabaseLock = true;
} else {
Expand Down Expand Up @@ -278,6 +283,86 @@ public void processAlterTable(AlterTableStmt stmt) throws UserException {
}
}

// entry of processing replace table
private void processReplaceTable(Database db, OlapTable origTable, List<AlterClause> alterClauses) throws UserException {
ReplaceTableClause clause = (ReplaceTableClause) alterClauses.get(0);
Preconditions.checkState(db.isWriteLockHeldByCurrentThread());

String oldTblName = origTable.getName();
String newTblName = clause.getTblName();
Table newTbl = db.getTable(newTblName);
if (newTbl == null || newTbl.getType() != TableType.OLAP) {
throw new DdlException("Table " + newTblName + " does not exist or is not OLAP table");
}
OlapTable olapNewTbl = (OlapTable) newTbl;

boolean swapTable = clause.isSwapTable();

// First, we need to check whether the table to be operated on can be renamed
olapNewTbl.checkAndSetName(oldTblName, true);
if (swapTable) {
origTable.checkAndSetName(newTblName, true);
}

replaceTableInternal(db, origTable, olapNewTbl, swapTable);

// write edit log
ReplaceTableOperationLog log = new ReplaceTableOperationLog(db.getId(), origTable.getId(), olapNewTbl.getId(), swapTable);
Catalog.getCurrentCatalog().getEditLog().logReplaceTable(log);

LOG.info("finish replacing table {} with table {}, is swap: {}", oldTblName, newTblName, swapTable);
}

public void replayReplaceTable(ReplaceTableOperationLog log) {
long dbId = log.getDbId();
long origTblId = log.getOrigTblId();
long newTblId = log.getNewTblId();
Database db = Catalog.getCurrentCatalog().getDb(dbId);
OlapTable origTable = (OlapTable) db.getTable(origTblId);
OlapTable newTbl = (OlapTable) db.getTable(newTblId);

try {
replaceTableInternal(db, origTable, newTbl, log.isSwapTable());
} catch (DdlException e) {
LOG.warn("should not happen", e);
}
LOG.info("finish replay replacing table {} with table {}, is swap: {}", origTblId, newTblId, log.isSwapTable());
}

/**
* The replace table operation works as follow:
* For example, REPLACE TABLE A WITH TABLE B.
* <p>
* 1. If "swapTable" is true, A will be renamed to B, and B will be renamed to A
* 1.1 check if A can be renamed to B (checking name conflict, etc...)
* 1.2 check if B can be renamed to A (checking name conflict, etc...)
* 1.3 rename B to A, drop old A, and add new A to database.
* 1.4 rename A to B, drop old B, and add new B to database.
* <p>
* 2. If "swapTable" is false, A will be dropped, and B will be renamed to A
* 1.1 check if B can be renamed to A (checking name conflict, etc...)
* 1.2 rename B to A, drop old A, and add new A to database.
*/
private void replaceTableInternal(Database db, OlapTable origTable, OlapTable newTbl, boolean swapTable)
throws DdlException {
String oldTblName = origTable.getName();
String newTblName = newTbl.getName();

// drop origin table and new table
db.dropTable(oldTblName);
db.dropTable(newTblName);

// rename new table name to origin table name and add it to database
newTbl.checkAndSetName(oldTblName, false);
db.createTable(newTbl);

if (swapTable) {
// rename origin table name to new table name and add it to database
origTable.checkAndSetName(newTblName, false);
db.createTable(origTable);
}
}

public void processAlterView(AlterViewStmt stmt, ConnectContext ctx) throws UserException {
TableName dbTableName = stmt.getTbl();
String dbName = dbTableName.getDb();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ public enum AlterOpType {
MODIFY_TABLE_PROPERTY_SYNC, // Some operations are performed synchronously, so we distinguish them by suffix _SYNC
// others operation, such as add/drop backend. currently we do not care about them
ALTER_OTHER,

INVALID_OP,
ENABLE_FEATURE;

ENABLE_FEATURE,
REPLACE_TABLE,
INVALID_OP; // INVALID_OP must be the last one

// true means 2 operations have no conflict.
public static Boolean[][] COMPATIBITLITY_MATRIX;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ public boolean hasRenameOp() {
return currentOps.contains(AlterOpType.RENAME);
}

public boolean hasReplaceTableOp() {
return currentOps.contains(AlterOpType.REPLACE_TABLE);
}

public boolean contains(AlterOpType op) {
return currentOps.contains(op);
}
Expand Down Expand Up @@ -103,4 +107,6 @@ public boolean hasEnableFeatureOP() {
public String toString() {
return Joiner.on(", ").join(currentOps);
}


}
Loading