1 0

java从数据库读取百万级数据保存到text文件中,速度慢,怎么解决0

代码如下,做一个数据脚本的备份与还原,从数据库查询所有记录,拼接成插入语句,数据库中有600多万条数据,在自的电脑上试,写到txt文件中足足花了半个小时的时间啊。。。。。不知道哪里有问题,麻烦各位指点一下

/**
	 * 如果记录大于10000行,则 分页抓取,每次抓取10000条,这里只适应于在mysql</br>
	 * @param rowCount
	 *            总记录数
	 * @param table
	 *            表名
	 * @param writer
	 *            输入流
	 */
	private static BufferedWriter fetchByPage(int rowCount, String table,
			BufferedWriter writer) {
		final int fetchSize = 10000;
		final int pageSize = rowCount % fetchSize == 0 ? rowCount / fetchSize
				: rowCount / fetchSize + 1;
		int currentPage = 1;
		Connection conn = null;
		Statement stsm = null;
		ResultSet rs = null;
		try {
			conn = newConnection();
			conn.setAutoCommit(false);
			stsm = conn.createStatement();
			if (isSqlServer(conn)) {
				writer
						.write("SET IDENTITY_INSERT [dbo].[" + table
								+ "] ON; \n");
			} else {
				writer.write("SET FOREIGN_KEY_CHECKS=0;\n"); // 默认是mysql
			}
			while (currentPage <= pageSize) {
				String sql = "select *  from " + table + " limit "
						+ (currentPage - 1) * fetchSize + "," + fetchSize;
				rs = stsm.executeQuery(sql);
				writeByRow(conn, table, rs, writer);
				currentPage++;

			}
			if (isSqlServer(conn)) {
				writer.write("SET IDENTITY_INSERT [dbo].[" + table
						+ "] OFF; \n");
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (conn != null) {
				try {
					if (!conn.isClosed())
						conn.close();
					if (stsm != null)
						stsm.close();
					if (rs != null)
						rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}
		return writer;

	}




private static BufferedWriter writeByRow(Connection conn, String tableName,
			ResultSet rs, BufferedWriter writer) throws Exception {
		while (rs.next()) {
			StringBuilder insertSql = new StringBuilder();
			insertSql.append("insert into ");
			String[] columnNames = getColumnNames(rs);
			if (isSqlServer(conn)) {
				insertSql.append("[" + tableName + "] (");
				for (String columnName : columnNames) {
					insertSql.append("[" + columnName + "],");
				}
			} else {
				insertSql.append("`" + tableName + "`(");
				for (String columnName : columnNames) {
					insertSql.append("`" + columnName + "`,");
				}
			}
			insertSql.deleteCharAt(insertSql.length() - 1);
			insertSql.append(")");
			insertSql.append("  values(");
			for (int i = 0; i < columnNames.length; i++) {
				String columnClassName = rs.getMetaData().getColumnClassName(
						i + 1);
				if (rs.getObject(i + 1) != null) {

					if (columnClassName.equalsIgnoreCase("java.lang.String")) {
						String strValue = rs.getString(columnNames[i]);

						strValue = strValue.replaceAll("\r", "\\\\r");
						strValue = strValue.replaceAll("\n", "\\\\n");
						insertSql.append("'" + strValue + "',");
					} else {
						insertSql.append("'" + rs.getObject(i + 1) + "',");
					}
				} else {
					insertSql.append(rs.getObject(i + 1) + ",");
				}
			}
			int index = insertSql.toString().lastIndexOf(",");
			String sqlText = insertSql.toString().substring(0, index) + ")";

			writer.write(sqlText + ";\n");
		}

		return writer;
	}


2013年4月19日 20:33

7个答案 按时间排序 按投票排序

0 0

采纳的答案

这种方式确实本身就有问题,性能不会很高,像MySQL本身就有备份还原数据库的命令:
%MYSQL_HOME%\bin>mysqldump -uroot -proot DB_NAME > "D:/DB_NAME_BAK.sql"

当然这种方式一次性导出,针对大数据量可能确实不行。

LZ现在的方式,首当其冲的问题就是:每从数据库查询一条数据就生成SQL并写到文件中。
程序效率低的原因分析:
这必然导致效率极低,因为数据库查询时的阻塞会导致整个任务暂停,这时既不生成SQL也不写文件;写文件时的阻塞也会导致整个任务暂停,这时也不再查询数据库了。这样当然效率很低了,因为这两种阻塞不断发生,导致整个任务很大一部分时间啥也没干,CPU闲置。

一、初步优化的方案:
“数据库查询的操作”和“生成SQL并写文件”分开来,用两个线程去做:
* 一个线程从数据库查询数据并简单处理(比如把每条数据放在一个map中,甚至放在一个数组中,这样速度更快,但是要在程序中控制,要清楚数组中每个元素是什么值),然后将简单处理后的数据放到一个队列中。
* 另一个线程负责从队列中读取简单处理过的数据,生成SQL,然后写入到文件中。

注意点:进行这一步优化后,那个队列需要重点实现,应该是线程安全的,因为两个线程都要访问。典型的消费者模式。

二、进一步的优化方案:
按照方案一优化后,效率有所提升,但还是达不到所需的性能要求,那么进一步进行优化。方案一中,最大的性能瓶颈可能是访问数据库的那个线程,可以考虑用多个线程并发访问数据库,但是这个线程也不能太多,太多也会慢,要通过具体实践取各平衡点。

注意点:这里要注意几个并发访问数据库的线程的分工,比如每个线程各负责某个时间段的数据,得有一个总线程负责调度。

三、再一步的优化方案:
按照方案二优化后,还可以在一个地方优化,哪里呢?那就是除了访问数据库之外的另一个可能阻塞的地方——写文件。这里也可以考虑多线程并发,但是不要多个线程写一个文件,可以每个线程写一个文件,最后把多各文件进行汇总,就得到了最终的数据库备份脚本。

另外有一个方案是——每个访问数据库的线程对应一个生成SQL并写文件的线程,然后一个总线程,总线程负责给每个问数据库的线程分配任务,最后把所有SQL文件汇总成最终结果。


LZ先按照第一个方案优化下,这个是必须的。不满足再进行后续优化。

2013年4月19日 21:52
1 0

像这种东西 还是交给数据库来的快  可以考虑下多线程并发查 然后单线程写
时间很大一部分花在了网络io上

2013年4月19日 20:42
0 0

使用数据库自己的备份 举个例子oracle 采用sqlload

2013年4月20日 02:00
0 0

直接调用mysqldump
Runtime.getRuntime().exec("%MYSQL_HOME%\bin>mysqldump -uroot -proot DB_NAME > D:/DB_NAME_BAK.sql");

2013年4月20日 00:33
0 0

这就不是java干的活,强扭的瓜不甜  数据库备份当然是用数据库干啊

2013年4月19日 21:05
0 0

每次都导出这么多数据?

2013年4月19日 21:01
0 0

你这种方式本身就有问题啊。
600万全表数据,肯定不适合使用sql方式导出啊,就算你花费时间生成这样的sql,到时候还原时,批量更新或插入也会非常慢的。什么数据库?为何不做增量备份呢?拼接sql的方式不如用脚本来备份。

2013年4月19日 20:42

相关推荐

    java数据库连接,并将数据库内容存放到txt文件

    java连接oracle数据库,并将从数据库中读取到得内容存放到txt文件中

    从Excel中读取数据导入到数据库中

    本文将详细阐述如何从Excel文件中读取数据并将其导入到数据库中,重点处理合并单元格和超过4000字符的数据列。 首先,我们需要理解Excel是常用的数据存储和处理工具,而数据库如MySQL、SQL Server、Oracle等则用于...

    java一次性查询处理几百万数据解决方法

    ### Java一次性查询处理几百万数据解决方法 在Java开发中,处理大数据量是常见的需求之一,特别是当数据规模达到几百万级别时,如何高效、稳定地处理这些数据变得尤为重要。本文将详细介绍一种Java一次性查询处理几...

    java实现读取html网页文件

    总结来说,Java通过I/O流可以轻松读取本地HTML文件,结合`Jsoup`库可以方便地处理HTML内容,最后使用JDBC将处理后的数据保存到数据库。这些都是Java开发中常用的技术,对于网络编程和数据处理非常实用。

    将数据库数据导出到word excel txt文件中源码。

    本篇将详细讲解如何使用源码实现从数据库中导出数据到Word、Excel和TXT文件。 首先,让我们了解一下这三个文件格式的特点: 1. **Word**:Microsoft Word是一款流行的文档处理软件,适用于创建结构化文档,如报告...

    Java从数据库中读取Blob对象图片并显示的方法

    在Java编程中,Blob(Binary Large Object)对象用于存储大量二进制数据,如图片、音频或视频文件。当这些数据存储在数据库中时,我们需要有合适的方法来读取并显示它们。这里我们主要探讨两种Java从数据库中读取...

    数据导入到excel和读取excel数据到数据库

    本文将详细讲解如何将数据导入到Excel以及如何从Excel读取数据并导入到数据库,以实现高效的数据操作。 一、数据导入到Excel 1. 手动导入:最简单的方式是直接复制其他源(如文本文件、数据库表)中的数据,然后在...

    读取数据库表数据转换成XML文件

    总之,从数据库读取数据并转换为XML文件是一个常见的需求,可以通过各种编程语言实现。这个过程涉及数据库查询、数据处理和XML序列化等技术,对于初学者来说,掌握这些技能将大大提升其在数据操作和集成方面的能力。

    安卓SQLite数据库相关-android读取本地.db文件实现不变数据本地化.rar

    在描述中提到的“读取本地.db文件”,通常是指将预填充的数据或者已经存在的一些数据库文件集成到应用中。这可以通过将.db文件放入应用的assets目录下,然后在应用启动时复制到数据库路径中完成。以下是如何实现这个...

    android读取sqlite数据库的数据并用listview显示

    至此,我们完成了从SQLite数据库读取数据并显示在ListView上的整个流程。当数据库中的数据发生变化时,只需刷新Adapter即可更新ListView的显示。这个示例对于理解Android中SQLite与ListView的交互非常有帮助,可以...

    java读取数据库替换文本字段并生成新的文本

    在Java编程中,读取数据库并替换文本字段然后生成新的文本是一个常见的任务,尤其是在处理大量数据或者进行数据处理与分析的场景。以下是一些相关的知识点: 1. **JDBC(Java Database Connectivity)**:Java访问...

    使用java连接数据库按需生成oracle卸数装数的control、selectSQL、建表ddl语句等文件

    在IT行业中,数据库管理和数据迁移是一项重要任务,尤其是在Oracle数据库这样的大型企业级系统中。Java作为一种广泛应用的编程语言,能够帮助我们实现与数据库的交互,完成各种自动化操作,包括生成控制文件(CTL)、...

    java解析xml并导入数据库(dom4j).doc

    Java 解析 XML 并导入数据库是指使用 Java 语言将 XML 文件解析并将其内容导入到数据库中。下面是使用 DOM4J 库来实现此功能的相关知识点: 一、XML 文件解析 XML(Extensible Markup Language)是一种标记语言,...

    word读取内容并操作存储数据库

    在这个场景下,我们需要使用Node.js来读取Word文档的内容,并将其解析后存储到数据库中。以下是一系列相关知识点的详细解释: 1. **Node.js**: Node.js是一个基于Chrome V8引擎的JavaScript运行环境,它允许我们在...

    android 读取本地中国城市数据库

    1. 数据导入:城市数据可以预先导入到SQLite数据库中,通常通过在应用安装时执行SQL脚本或加载预定义的数据文件(如CSV或JSON)完成。 2. 动态加载:如果数据库文件(如`CityData_1.db`)已包含城市数据,可以在应用...

    利用存储过程将Excel中数据导入到数据库表中

    本话题聚焦于如何通过存储过程将Excel中的数据高效地导入到数据库表中。存储过程是预编译的SQL语句集合,能够提高执行效率,同时提供更好的安全性和可维护性。在这个过程中,我们通常会使用编程语言与数据库进行交互...

    java中读取ORACLE中BLOB字段存储的图片

    ### Java中读取Oracle数据库BLOB字段存储的图片方法详解 #### 一、背景与目的 在实际的应用开发过程中,经常会有将图片等二进制数据存入数据库的需求。Oracle数据库支持通过BLOB(Binary Large Object)类型来存储...

    WinRunner之读取数据库中数据

    根据给定的信息,本文将详细解释如何在WinRunner中实现从数据库(包括SQL Server 2005和Oracle)读取数据的过程,并提供相应的代码示例。此外,还将讨论一些扩展应用,例如数据迁移。 ### WinRunner简介 WinRunner...

    highcharts实现从mysql数据库获取数据生成折线图

    在JSP页面`chart_data.jsp`中,你可以编写类似上面的Java代码来获取数据库数据并以JSON格式返回。记得处理好跨域问题,如果有必要的话。 总结起来,要实现"highcharts实现从mysql数据库获取数据生成折线图",你需要...

Global site tag (gtag.js) - Google Analytics