Insert Into語句的使用方式和MySQL等資料庫中Insert Into語句的使用方式類似。在Doris中,所有的資料寫入都是一個獨立的匯入作業。因此,本文將Insert Into作為一種匯入方式,介紹Insert Into的使用方法和最佳實務。
背景資訊
本文部分內容來源於Apache Doris,詳情請參見Introduction to Apache Doris。
主要的Insert Into命令包含以下兩種:
NSERT INTO tbl SELECT ...
INSERT INTO tbl (col1, col2, ...) VALUES (1, 2, ...), (1,3, ...);
重要該命令僅用於Demo,請勿使用在測試或生產環境中。
匯入操作及返回結果
Insert Into命令需要通過MySQL協議提交,建立匯入請求會同步返回匯入結果。
匯入操作
Insert Into的使用樣本如下:
INSERT INTO tbl2 WITH LABEL label1 SELECT * FROM tbl3;
INSERT INTO tbl1 VALUES ("qweasdzxcqweasdzxc"), ("a");當需要使用CTE(Common Table Expressions) 作為insert操作中的查詢部分時,必須指定WITH LABEL和column list部分或者對CTE進行封裝,樣本如下。
INSERT INTO tbl1 WITH LABEL label1
WITH cte1 AS (SELECT * FROM tbl1), cte2 AS (SELECT * FROM tbl2)
SELECT k1 FROM cte1 JOIN cte2 WHERE cte1.k1 = 1;
INSERT INTO tbl1 (k1)
WITH cte1 AS (SELECT * FROM tbl1), cte2 AS (SELECT * FROM tbl2)
SELECT k1 FROM cte1 JOIN cte2 WHERE cte1.k1 = 1;
INSERT INTO tbl1 (k1)
select * from (
WITH cte1 AS (SELECT * FROM tbl1), cte2 AS (SELECT * FROM tbl2)
SELECT k1 FROM cte1 JOIN cte2 WHERE cte1.k1 = 1) as ret樣本中的參數說明,詳情請參見INSERT INTO命令或者執行HELP INSERT來查看。
返回結果
Insert Into本身是一個SQL命令,其返回結果會根據執行結果的不同,分為以下幾種:
結果集為空白
如果Insert對應Select語句的結果集為空白,返回樣本如下。
mysql> insert into tbl1 select * from empty_tbl; Query OK, 0 rows affected (0.02 sec)Query OK表示執行成功,0 rows affected表示沒有資料被匯入。
結果集不為空白
在結果集不為空白的情況下,返回結果分為如下幾種情況:
Insert執行成功並可見。
mysql> insert into tbl1 select * from tbl2; Query OK, 4 rows affected (0.38 sec) {'label':'insert_8510c568-9eda-4173-9e36-6adc7d35****', 'status':'visible', 'txnId':'4005'} mysql> insert into tbl1 with label my_label1 select * from tbl2; Query OK, 4 rows affected (0.38 sec) {'label':'my_label1', 'status':'visible', 'txnId':'4005'} mysql> insert into tbl1 select * from tbl2; Query OK, 2 rows affected, 2 warnings (0.31 sec) {'label':'insert_f0747f0e-7a35-46e2-affa-13a235f4****', 'status':'visible', 'txnId':'4005'} mysql> insert into tbl1 select * from tbl2; Query OK, 2 rows affected, 2 warnings (0.31 sec) {'label':'insert_f0747f0e-7a35-46e2-affa-13a235f4****', 'status':'committed', 'txnId':'4005'}Query OK表示執行成功,4 rows affected表示總共有4行資料被匯入,2 warnings表示被過濾的行數。
同時會返回一個JSON串,樣本如下:
{'label':'my_label1', 'status':'visible', 'txnId':'4005'} {'label':'insert_f0747f0e-7a35-46e2-affa-13a235f4****', 'status':'committed', 'txnId':'4005'} {'label':'my_label1', 'status':'visible', 'txnId':'4005', 'err':'some other error'}label:您指定的Label或自動產生的Label。Label是該Insert Into匯入作業的標識,每個匯入作業都有一個在單database內部唯一的Label。
status:表示匯入資料是否可見。如果可見,顯示visible,如果不可見,顯示committed。
txnId:該Insert對應的匯入事務的id。
err:顯示一些其他非預期錯誤。
您可以使用SHOW LOAD語句查看被過濾的行,樣本如下。返回結果中的URL可以用於查詢錯誤的資料。
show load where label="xxx";資料不可見是一個臨時狀態,資料最終是一定可見的。可以通過SHOW TRANSACTION語句查看這批資料的可見狀態,樣本如下。返回結果中的TransactionStatus列如果為visible,則表述資料可見。
show transaction where id=4005;Insert執行失敗。
執行失敗表示沒有任何資料被成功匯入,返回樣本如下。
mysql> insert into tbl1 select * from tbl2 where k1 = "a"; ERROR 1064 (HY000): all partitions have no load data. url: http://10.74.xx.xx:8042/api/_load_error_log?file=__shard_2/error_log_insert_stmt_ba8bb9e158e4879-ae8de8507c0b****_ba8bb9e158e4879_ae8de8507c0b****其中
ERROR 1064 (HY000): all partitions have no load data顯示失敗原因。後面的url可以用於查詢錯誤的資料。
綜上,對於Insert操作返回結果的正確處理邏輯為:
如果返回結果為ERROR 1064 (HY000),則表示匯入失敗。
如果返回結果為Query OK,則表示執行成功。
如果rows affected為0,表示結果集為空白,沒有資料被匯入。
如果rows affected大於0:
如果status為committed,表示資料不可見,需要通過SHOW TRANSACTION語句查看狀態直到visible。
如果status為visible,表示資料匯入成功。
如果warnings大於0,表示有資料被過濾,可以通過SHOW LOAD語句擷取URL查看被過濾的行。
SHOW LAST INSERT
上面介紹了如何根據Insert操作的返回結果進行後續處理。但一些語言的MySQL類庫中很難擷取返回結果中的JSON字串。因此,Doris還提供了SHOW LAST INSERT命令來顯式的擷取最近一次Insert操作的結果。當執行完一個Insert操作後,可以在同一Session串連中執行SHOW LAST INSERT,該命令會返回最近一次Insert操作的結果。例如:
mysql> show last insert\G
*************************** 1. row ***************************
TransactionId: 640**
Label: insert_ba8f33aea9544866-8ed77e2844d0****
Database: default_cluster:db1
Table: t1
TransactionStatus: VISIBLE
LoadedRows: 2
FilteredRows: 0 該命令會返回Insert以及對應事務的詳細資料。因此,您可以在每次執行完Insert操作後,繼續執行show last insert命令來擷取Insert的結果。
該命令只會返回在同一Session串連中,最近一次Insert操作的結果。如果串連斷開或更換了新的串連,則將返回空集。
相關係統配置
FE配置
timeout:匯入任務的逾時時間(以秒為單位)。匯入任務在設定的timeout時間內未完成則會被系統取消,變成CANCELLED。目前Insert Into暫不支援自訂匯入的timeout時間,所有Insert Into匯入的逾時時間是統一的,預設的timeout 時間為1小時。如果匯入的源檔案無法在規定時間內完成匯入,則需要調整FE的參數insert_load_default_timeout_second。同時Insert Into語句受到Session變數query_timeout的限制,可以通過SET query_timeout = xxx; 來增加逾時時間,單位是秒。
Session變數
enable_insert_strict:Insert Into匯入本身不能控制匯入可容忍的錯誤率。您只能通過Session參數enable_insert_strict控制。當該參數設定為false時,表示至少有一條資料被正確匯入,則返回成功;如果有失敗資料,則還會返回一個Label。當該參數設定為true時,表示如果有一條資料錯誤,則匯入失敗。預設為false。可通過
SET enable_insert_strict = true;來設定。query_timeout:Insert Into本身也是一個SQL命令,因此也受到Session變數query_timeout的限制。可以通過
SET query_timeout = xxx;來增加逾時時間,單位是秒。
最佳實務
應用情境
僅匯入幾條測試資料,驗證Doris系統的功能,適合使用INSERT INTO VALUES文法,其與MySql文法相同。
將已經在Doris表中的資料進行ETL轉換並匯入到一個新的Doris表中,適合使用INSERT INTO SELECT文法。
建立一種外部表格,如MySQL外部表格映射一張MySQL系統中的表,或者建立Broker外部表格來映射HDFS上的資料檔案。然後通過INSERT INTO SELECT文法將外部表格中的資料匯入到Doris表中儲存。
資料量
Insert Into對資料量沒有限制,也支援巨量資料量匯入。但Insert Into有預設的逾時時間,如果您預估的匯入資料量過大,需要修改系統的Insert Into匯入逾時時間。
例如,當匯入資料量為36 GB時,匯入時間約小於等於3600s*10 M/s。其中10 M/s是最大匯入限速,您需要根據當前叢集情況計算出平均的匯入速度來替換公式中的10 M/s。
完整樣本
在資料庫sales中有表store_sales,又建立表bj_store_sales,希望將store_sales中銷售記錄在bj的資料匯入到表bj_store_sales中,匯入的資料量約為10 GB,當前叢集的平均匯入速度約為5 M/s。
store_sales schema:
(id, total, user_id, sale_timestamp, region)
bj_store_sales schema:
(id, total, user_id, sale_timestamp)判斷是否要修改Insert Into的預設逾時時間。
計算匯入的大概時間 10 GB / 5 M/s = 2000s 修改FE配置 insert_load_default_timeout_second = 2000建立匯入任務。
由於希望將一張表中的資料做ETL並匯入到目標表中,所以應該使用Insert into query_stmt方式匯入。
INSERT INTO bj_store_sales WITH LABEL `label` SELECT id, total, user_id, sale_timestamp FROM store_sales where region = "bj";