向DB表中插入100W条记录

本文提供了一种在MySQL和Oracle数据库中批量插入大量数据的方法,利用存储过程实现递归插入,并通过参数化LIMIT子句来精确控制插入的数据量。
有机会出笔试题的时候,下面是备用方案。
题:向数据库中插入100W条记录,表自定义,数据可重复。

delimiter $$
drop procedure if exists insertRecords $$
create procedure insertRecords(num int)
begin
declare mi tinyint default 0;
drop table if exists recursive;
create table recursive(id int auto_increment, name varchar(20),primary key(id));
insert into recursive(name) values('anna');
while(power(2,mi)<num) do
set mi=mi+1;
insert into recursive(name) select name from recursive;
end while;
delete from recursive where id > num;
end
$$ delimiter ;

MySQL 存储过程是从 MySQL 5.0 开始增加的新功能。使用delimiter $$ 来定义语句结束符,创建完成后,还原;因为MySQL默认以";"为分隔符,过程体的每一句都被MySQL以存储过程编译,则编译过程会报错。drop procedure if exists...在此已经执行了。
上述代码的第13行,可以使用带参数的limit来改进,如下,

delimiter $$
drop procedure if exists insertRecords $$
create procedure insertRecords(num int)
begin
declare mi tinyint default 1;
declare more int default 0;
drop table if exists recursive;
create table recursive(id int auto_increment, name varchar(20),primary key(id));
insert into recursive(name) values('anna');
while(power(2,mi)<num) do
set mi=mi+1;
insert into recursive(name) select name from recursive;
end while;
set more=num-power(2,(mi-1));
set @stmt='insert into recursive(name) select name from recursive limit ?';
prepare newSql from @stmt;
set @arg=more;
execute newSql using @arg;
deallocate prepare newSql;
end
$$ delimiter ;

To deallocate a prepared statement produced with PREPARE, use a DEALLOCATE PREPARE statement that refers to the prepared statement name. Attempting to execute a prepared statement after deallocating it results in an error.看得懂,不会翻译...执行存储过程后才开始关于表的DDL&DML。

call insertRecords(1000000);

最后查看记录条数。

select count(id) num from recursive;


--------下面给出Oracle版-------------------------------
先创建序列用于自增,如下。

create sequence auto_increment;

然后创建表,blabla...

create table recursive(id number(10) primary key, name varchar2(20));

接着整个触发器,作用:向表中插入数据时实现自动自增功能。

create or replace trigger insert_recursive_trigger
before insert on recursive
for each row
begin
select auto_increment.nextval into :new.id from dual;
end;
/

插入一条记录,以备后用。

insert into recursive(name) values('anna');

后面写个存储过程,用于插入数据,下面13行后面的 :1是占位符 。

create or replace procedure insertRecords(num number)
is
mi number(2) default 1;
more number(10) default 0;
dml_insert varchar2(100);
begin
dml_insert :='insert into recursive(name) select name from recursive';
while(power(2,mi)<num) loop
mi :=mi+1;
execute immediate dml_insert ;
end loop;
more :=num-power(2,(mi-1));
dml_insert :='insert into recursive(name) select name from recursive where rownum<=:1';
execute immediate dml_insert using more;
end ;
/

最后测试下,只用了10w条,有点慢,是由于用了触发器的缘故。

exec insertRecords(100000);
select count(id) num from recursive;
select count(distinct(id)) from recursive;

之前也是把所有Orable语句集成到insertRecords存储过程里,发现有关于execute immediate的权限问题,没深入探索,就拆开了。感兴趣的童鞋给加个MS SqlServer(刚卸载不久,暂不想再装)版的。

1.若总分为10分,写出 insert into .. select ..即可得5分。
2.若之用for循环100w次插入数据,得3分。

[注]:程序实用性不大,主要考察能力。
上述代码通过了MySql5.0、Oracle10g_r1编译和运行。
<think>嗯,用户问的是如何将超过100数据插入到Elasticsearch里。首先,我需要考虑数据量大的时候常见的挑战和处理方法。可能用户遇到了性能问题,或者正在设计一个数据导入的方案。 首先,直接单插入肯定不行,100数据的话,速度太慢,网络开销也大。应该建议批量处理,比如使用Bulk API。但是批量处理的时候要注意批次大小,不能太大,否则内存可能撑不住。通常建议每批1000到5000,或者根据文档大小调整,比如每批5-15MB。用户可能需要根据实际情况测试调整。 然后,数据源是数据库,比如MySQL,可能需要用Logstash或者其他的ETL工具。Logstash的jdbc插件可以定时拉取数据,但百万级数据的话,一次性导入可能需要分页查询。不过分页查询深分页会有性能问题,可以用基于id的范围查询,或者按时间分片,这样效率更高。 另外,用程序自己处理的话,可能需要多线程或者异步的方式。比如用Java的BulkProcessor,自动管理批量提交,设置并发数,这样能提高吞吐量。不过线程数不能太多,否则ES集群压力大,可能适得其反。需要监控集群的负载情况,调整参数。 还有数据结构优化,比如避免嵌套字段太多,禁用不必要的索引,或者调整refresh_interval,暂时关闭副本,等数据导入完再恢复。这些设置能减少写入时的开销,提升速度。 还有考虑数据导入过程中出错的情况,需要有重试机制,记录失败的操作,可能用队列来暂存,然后重试。同时,监控写入速度,调整参数,比如批次大小、线程数,找到最佳组合。 可能用户还需要考虑数据更新后的同步问题,比如后续的数据变更如何同步到ES。如果是全量导入,那可能是一次性的,但如果是持续导入,可能需要binlog之类的实时同步工具,比如Canal。不过用户的问题可能只是初次导入,所以先解决当前的问题。 总结一下,步骤应该是:1. 使用Bulk API批量插入;2. 优化数据读取,比如分页或游标;3. 多线程/异步处理提高效率;4. 调整ES配置,暂时优化写入性能;5. 错误处理和重试机制;6. 完成后恢复配置,比如副本和刷新间隔。 还需要提醒用户测试不同的批次大小和线程数,因为不同的环境和数据情况可能会有不同的最优解。另外,如果数据源是数据库,是否可以使用索引来加速查询,比如按id或时间排序,减少查询时间。最后,监控ES的写入性能,观察是否有瓶颈,比如CPU、内存、磁盘IO等,及时调整。</think>将100万+数据高效插入Elasticsearch可按照以下步骤进行: 一、基础优化方案 1. 批量写入(Bulk API) ```bash POST _bulk { "index" : { "_index" : "your_index" } } { "field1":"value1", "field2":123 } { "index" : { "_index" : "your_index" } } { "field1":"value2", "field2":456 } ``` - 建议批次大小:每批1000-5000或5-15MB - Java示例使用`BulkProcessor`自动管理批次 2. 并行处理 - 推荐设置3-5个并行线程(根据集群规模调整) - Python示例: ```python from concurrent.futures import ThreadPoolExecutor def batch_insert(batch): # 执行bulk操作 with ThreadPoolExecutor(max_workers=4) as executor: executor.map(batch_insert, data_chunks) ``` 二、高级优化策略 1. 集群配置调整(临时) ```json PUT your_index/_settings { "index": { "refresh_interval": "-1", "number_of_replicas": "0" } } ``` 数据导入完成后恢复: ```json PUT your_index/_settings { "index": { "refresh_interval": "1s", "number_of_replicas": "1" } } ``` 2. 数据分片优化 ```json PUT your_index { "settings": { "number_of_shards": 5, // 根据数据总量设置 "number_of_replicas": 0 // 导入时禁用副本 } } ``` 三、数据源处理技巧 1. 数据库分页优化(MySQL示例) ```sql SELECT * FROM table WHERE id > ? ORDER BY id LIMIT 5000 ``` 使用游标方式替代传统分页 2. Logstash配置示例 ```conf input { jdbc { jdbc_driver_library => "mysql-connector-java-8.0.25.jar" jdbc_driver_class => "com.mysql.jdbc.Driver" jdbc_connection_string => "jdbc:mysql://localhost:3306/db" jdbc_user => "root" jdbc_paging_enabled => true tracking_column => "id" schedule => "* * * * *" statement => "SELECT * FROM table WHERE id > :sql_last_value" } } output { elasticsearch { hosts => ["localhost:9200"] index => "your_index" document_id => "%{id}" } } ``` 四、性能监控与调优 1. 关键监控指标: - Bulk队列等待时间(cluster_metrics.thread_pools.bulk.queue) - Merge操作频率(indices_stats.merges) - CPU使用率(nodes_stats.process.cpu.percent) 2. 常见瓶颈处理: - 磁盘IO过高:升级SSD或增加节点 - 内存不足:减少批次大小,增加堆内存(建议不超过32GB) - 网络延迟:压缩传输数据(设置`http.compression: true`) 五、特殊场景处理 1. 持续增量同步方案: - 数据库CDC方案(如Debezium+ Kafka Connect) - 基于时间戳的滚动写入 2. 数据去重策略: ```json PUT your_index { "mappings": { "_meta": { "deduplication_field": "unique_id" } } } ``` 六、最佳实践建议 1. 数据预处理: - 提前转换日期格式(避免动态映射) - 禁用不必要的字段分词 - 设置合理的mapping类型 2. 写入性能基准测试(示例数据): ``` | 批次大小 | 线程数 | 写入速度(docs/s) | |----------|--------|--------------------| | 1000 | 2 | 8,000 | | 3000 | 4 | 23,000 | | 5000 | 5 | 35,000 | ``` 实际生产环境中,通过优化配置通常可以达到3-5万/秒的写入速度。建议在正式导入前进行小批量测试(约10万),根据测试结果调整参数。 注意:完成数据导入后务必执行`_forcemerge`操作优化段合并: ```bash POST your_index/_forcemerge?max_num_segments=1 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值