我有幾個存儲日常訂單,客戶和銷售人員的表。然而,由於列具有不適當的數據值和類型,缺少索引和分區等,因此架構設計不佳。我重新設計了一個新架構,並使用破壞的表填充新表。我現在堅持填充日常訂單表(大約有10M條記錄)。加速MySQL插入選擇進入1000萬條記錄
附加的數據定義和SQL腳本來填充表。
表定義
CREATE TABLE IF NOT EXISTS `testing`.`Orders` (
`order_ID` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`ord_id` BIGINT UNSIGNED NOT NULL,
`create_time` DATETIME NOT NULL,
`create_date` DATE NOT NULL,
`cust_id` MEDIUMINT UNSIGNED NOT NULL,
`cust_mob` BIGINT UNSIGNED NULL,
`sales_id` MEDIUMINT UNSIGNED NULL,
`sales_mob` BIGINT UNSIGNED NULL,
`sales_flag` TINYINT UNSIGNED NULL,
`comm_flag` TINYINT UNSIGNED NULL,
`extraprice` TINYINT UNSIGNED NULL,
PRIMARY KEY (`order_ID`),
INDEX `Date_cust_id` (`create_date` ASC, `cust_id` ASC),
INDEX `Date_cust_mob` (`create_date` ASC, `cust_mob` ASC),
INDEX `Date_dri_id` (`create_date` ASC, `sales_id` ASC),
INDEX `Date_dri_mob` (`create_date` ASC, `sales_mob` ASC),
INDEX `Date_cust` (`create_date` ASC, `cust_id` ASC, `cstu_mob` ASC),
INDEX `Date_dri` (`create_date` ASC, `sales_id` ASC, `sales_mob` ASC),
INDEX `cust` (`cust_id` ASC, `cust_mob` ASC),
INDEX `dri` (`sales_id` ASC, `sales_mob` ASC),
UNIQUE INDEX `ord_id_UNIQUE` (`ord_id` ASC)
)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;
該腳本來填充表,涉及兩個左連接表:帕格表6XXķ記錄和DRI表3倍ķ記錄。
SET SQL_SAFE_UPDATES=0;
SET SQL_MODE='';
DROP PROCEDURE IF EXISTS testing.populate_ord1;
DELIMITER $$
CREATE PROCEDURE testing.populate_ord1()
BEGIN
PREPARE stmt
FROM "
INSERT INTO testing.Orders
SELECT
1
,ord_id
,CASE WHEN TRIM(create_time) ='NULL' THEN NULL ELSE STR_TO_DATE(substring(create_time,1,19), '%Y-%m-%d %H:%i:%s') END AS create_time
,CASE WHEN TRIM(create_time) ='NULL' THEN NULL ELSE DATE(STR_TO_DATE(substring(create_time,1,19), '%Y-%m-%d %H:%i:%s')) END AS create_date
,CASE WHEN TRIM(ord.cust_id) = 'NULL' THEN NULL else pag.cust_id END as cust_id
,CASE WHEN TRIM(ord.mob) = 'NULL' THEN NULL else pag.cust_mob END as cust_mob
,CASE WHEN TRIM(ord.sales_id) = 'NULL' THEN NULL else dri.sales_id END as sales_id
,CASE WHEN TRIM(ord.mob1) = 'NULL' THEN NULL else dri.sales_mob END as sales_mob
,CASE WHEN TRIM(sales_flag) ='NULL' THEN NULL ELSE CONVERT(TRIM(sales_flag),UNSIGNED INTEGER) end AS sales_flag
,CASE WHEN TRIM(comm_flag) ='NULL' THEN NULL ELSE CONVERT(TRIM(comm_flag),UNSIGNED INTEGER) end AS comm_flag
,CASE WHEN TRIM(extraprice) ='NULL' THEN NULL ELSE CONVERT(TRIM(extraprice),UNSIGNED INTEGER) end AS extraprice
FROM testing.ord_table ord
LEFT JOIN
(SELECT cust_id,customer_id,cust_mob FROM testing.Passenger) pag
ON TRIM(ord.customer_id) = TRIM(pag.pag_id)
AND TRIM(ord.mob) = TRIM(pag.passenger_mob)
LEFT JOIN
(SELECT sales_id,salesperson_id,sales_mob FROM testing.sales) dri
ON TRIM(ord.salesperson_id) = TRIM(dri.sales_id)
AND TRIM(ord.mob1) = TRIM(dri.sales_mob)
WHERE ord_id != 'NULL' AND create_time IS NOT NULL AND create_time != 'NULL' AND YEAR(create_time) = ? AND MONTH(create_time) = ? AND DAY(create_time) = ?
GROUP BY ord_id
ON DUPLICATE KEY UPDATE ord_id = ord_id
;
";
SET @y = 2014, @m = 9, @d = 1;
WHILE @y<= 2014 DO
WHILE @m<= 12 DO
SET @d = 1;
WHILE @d<= 31 DO
EXECUTE stmt USING @y, @m, @d;
SET @d = @d + 1;
END WHILE;
SET @m = @m + 1;
END WHILE;
SET @y = @y + 1;
SET @m = 1;
END WHILE;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;
set autocommit=0;
call testing.populate_ord1();
COMMIT;
我沒有填充表中的任何記錄。有時會引發鎖定等待超時錯誤或數據類型錯誤,或者只需要很長時間(2天),我懷疑它甚至在做任何工作。
我在網上搜索了一下,並將以下設置添加到my.cnf。
innodb_autoinc_lock_mode = 2
innodb_lock_wait_time_out = 150
innodb_flush_log_at_trx_commit =2
innodb_buffer_pool_size = 14G
有人會建議我如何有效地完成同樣的任務嗎?上面的代碼運行時沒有任何語法錯誤。如果有任何命名混淆,請告訴我是否需要澄清這一點,因爲我稍微調整了這些變量表。
實際上在某些列中是否有文本字符串'「NULL」?這與_null不同,'NULL'不能用'='來測試。 –
這是一次性行動,還是一種預定的工作? – Sal
是'NULL'作爲列值存在,它是一次性任務。 – yukclam9