<think>我们正在讨论达梦数据库(DM)中批量插入数据的方法。根据引用内容,我们可以总结出几种常见的批量插入方式:
1. **使用存储过程循环插入**(引用[2]):
- 通过声明变量控制循环次数,逐条插入数据。
- 示例:插入100万条数据,但效率较低,因为每次循环都要执行一次插入。
2. **使用`INSERT INTO ... SELECT`结合伪表和`CONNECT BY`生成大量数据**(引用[3]):
- 利用达梦数据库的`dual`伪表和`CONNECT BY`语法生成指定行数的数据。
- 示例:通过`connect by level <= 10000000`生成1000万行数据,并利用随机函数生成各列的值。
3. **使用`MERGE INTO`语句进行批量插入(并可忽略主键重复)**(引用[1]的标题提到,但具体内容未给出,根据标题我们可以推测这是一种高级用法):
- `MERGE INTO`通常用于合并数据(更新或插入),但也可以用于批量插入并处理重复键(例如忽略重复)。
下面我们详细说明这三种方法:
### 方法1:存储过程循环插入
这种方法适用于数据量不是特别大(例如几万条)的情况,对于百万级以上数据量效率较低。
示例(来自引用[2]):
```sql
DECLARE
i INT := 1;
BEGIN
LOOP
i := i+1;
INSERT INTO dm_varchar (aes, sm4, sm4_a, email, phone, ssn, military, credit_card, job)
VALUES ('胡小芬', '北京xx网络技术有限公司', '北京市', 'xxx@yahoo.com', '15652996964', '210302199608124861', '武水电字第3632734号', '6227612145830440', '测试开发工程师');
EXIT WHEN i=1000000;
END LOOP;
END;
/
```
### 方法2:使用`INSERT INTO ... SELECT`和伪表生成大量数据
这是生成大量测试数据的高效方法,通过一条SQL语句即可插入大量数据。
示例(来自引用[3],并稍作解释):
```sql
INSERT INTO TMONTH_DATA(id, name, bir)
SELECT
rownum AS id,
dbms_random.string('x', 10) || '大方扣扣的妈妈网' || dbms_random.string('x', 10) AS random_string,
(TO_DATE('1991-01-01', 'YYYY-MM-DD') + DBMS_RANDOM.VALUE(0, SYSDATE - TO_DATE('1991-01-01', 'YYYY-MM-DD')))
FROM dual
CONNECT BY LEVEL <= 10000000;
```
说明:
- `dual`:达梦数据库中的伪表,用于生成数据。
- `CONNECT BY LEVEL <= n`:生成n行数据。
- `dbms_random.string('x', 10)`:生成10个由大写字母和数字组成的随机字符串。
- `DBMS_RANDOM.VALUE(a, b)`:生成a到b之间的随机数,这里用于生成随机日期。
### 方法3:使用`MERGE INTO`忽略重复主键插入
`MERGE INTO`语句通常用于根据源表数据更新或插入目标表。我们可以利用它来插入数据,并在遇到主键重复时忽略(不做任何操作)。
示例(假设目标表为`target_table`,源数据来自一个子查询或临时表):
```sql
MERGE INTO target_table t
USING (
-- 这里构造批量数据,可以是一个子查询或者临时表
SELECT ... FROM dual CONNECT BY ...
) s
ON (t.primary_key = s.primary_key) -- 根据主键匹配
WHEN NOT MATCHED THEN
INSERT (col1, col2, ...) VALUES (s.col1, s.col2, ...);
```
注意:这种方法需要有一个匹配条件(ON子句),并且只插入不匹配的行(即主键不重复的行)。这样可以避免主键重复错误。
### 性能比较
- 存储过程循环插入:效率最低,适合小批量数据。
- `INSERT INTO ... SELECT`:效率高,适合生成大量测试数据。
- `MERGE INTO`:效率较高,且可以处理重复数据,适合需要避免重复的批量插入。
### 注意事项
1. **事务管理**:批量插入时,如果数据量很大,建议分批次提交事务,避免大事务导致回滚段膨胀和性能下降。
2. **日志记录**:批量插入会产生大量日志,可以适当调整日志参数(如加大日志文件大小)或使用`nologging`选项(但需谨慎,以防数据丢失无法恢复)。
3. **约束和索引**:在批量插入前,可以考虑暂时禁用约束和索引,插入完成后再重建,以提高性能。
### 相关问题
1. 达梦数据库批量插入数据时如何提高性能?
2. 达梦数据库的`MERGE INTO`语句有哪些具体用法?
3. 如何避免批量插入时的主键重复错误?
4. 达梦数据库生成随机数据的方法有哪些?</think>### 达梦数据库(DM)批量插入数据方法详解
在达梦数据库中进行批量插入操作,主要有以下三种高效方法(附代码示例):
---
#### 方法1:存储过程循环插入(适合精确控制数据量)
```sql
DECLARE
i INT := 1; -- 初始化计数器
BEGIN
LOOP
INSERT INTO dm_varchar (aes, sm4, email)
VALUES ('张明', '上海科技', 'zhang@example.com'); -- 单条插入语句
i := i + 1;
EXIT WHEN i > 1000000; -- 插入100万条后退出
END LOOP;
COMMIT; -- 提交事务
END;
```
**特点**:
- 逐条插入,逻辑简单直观[^2]
- 需手动提交事务(`COMMIT`)
- 性能较低,适合百万级以下数据
---
#### 方法2:伪表+`CONNECT BY`批量生成(千万级数据首选)
```sql
INSERT INTO TMONTH_DATA(id, name, bir)
SELECT
ROWNUM,
DBMS_RANDOM.STRING('X', 10) || '公司' || DBMS_RANDOM.STRING('X', 10), -- 随机字符串
TO_DATE('1990-01-01', 'YYYY-MM-DD') + DBMS_RANDOM.VALUE(0, 12000) -- 随机日期
FROM DUAL
CONNECT BY LEVEL <= 10000000; -- 生成1000万行[^3]
```
**优势**:
1. **单SQL执行**:无需循环,效率提升10倍以上
2. **内置函数**:
- `DBMS_RANDOM.STRING()` 生成随机字符串
- `DBMS_RANDOM.VALUE()` 生成随机数
3. `CONNECT BY LEVEL` 快速生成序列
---
#### 方法3:`MERGE INTO`忽略重复(安全写入)
```sql
MERGE INTO target_table t
USING (
SELECT '李雷' AS name, '深圳' AS address FROM dual
UNION ALL
SELECT '韩梅梅', '广州' FROM dual
-- 可扩展更多数据行
) s ON (t.name = s.name) -- 匹配条件
WHEN NOT MATCHED THEN -- 仅插入不重复数据
INSERT (name, address) VALUES (s.name, s.address);
```
**核心价值**:
- 自动跳过主键/唯一键冲突[^1]
- 支持多数据源(子查询/临时表)
- 原子性操作(无需显式事务)
---
### ⚙️ 性能优化建议
1. **分批提交**:每50万条执行`COMMIT`避免大事务
```sql
FOR i IN 1..200 LOOP
INSERT ... CONNECT BY LEVEL <= 50000; -- 每次5万条
COMMIT;
END LOOP;
```
2. **禁用约束**:插入前禁用索引和约束
```sql
ALTER TABLE dm_varchar DISABLE CONSTRAINT CONS134215; -- 禁用约束
-- 执行批量插入
ALTER TABLE dm_varchar ENABLE CONSTRAINT CONS134215; -- 重新启用
```
3. **并行处理**:
```sql
ALTER SESSION ENABLE PARALLEL DML; -- 启用并行
INSERT /*+ PARALLEL(4) */ INTO ... -- 使用4个并行线程
```
---
### 测试数据生成技巧
```sql
-- 生成1亿测试数据
INSERT INTO big_data
SELECT
ROWNUM,
MOD(ROWNUM, 100), -- 取模分布
SYSDATE - DBMS_RANDOM.VALUE(1,3650), -- 10年内随机日期
RPAD('X', 200, 'Y') -- 200字节大字段
FROM DUAL CONNECT BY LEVEL <= 100000000;
```
---
### 相关问题
1. 达梦数据库如何实现批量更新与插入的原子操作?
2. 使用`CONNECT BY`生成数据时如何避免内存溢出?
3. 达梦与Oracle在批量插入语法上有哪些兼容性差异?
4. 如何监控大规模数据插入的性能瓶颈?
[^1]: 高级DBA教你达梦8国产数据库MergeInto批量插入并忽略主键重复报错特殊用法
[^2]: 达梦数据库使用存储过程批量插入100w条数据
[^3]: DM达梦数据库快速生成1000w数据