1. 程式人生 > >oracle導出多CSV文件的靠譜的

oracle導出多CSV文件的靠譜的

遍歷 mat sqlplus bsp 性能 rac 分割 export 是我

oracle導出多CSV文件的問題


----------------------------------------------------------------------

用ksh腳本從oracle數據庫中導出80w數據到csv文件,如用戶給定名字為a.csv(文件最大4000行記錄),則自動生產文件為a_1.csv,a_2.csv,...., a_200.csv

我已經實現了一個方法,但80w要導5小時,用戶沒法接受。如下:
sqlplus -s user/pwd @${SqlDir}/select_log.sql >/tmp/a.tmp
然後每read 4000行到文件a_1.csv,並且每隔4000行換一個文件名。


大家有什麽好方法嗎?註意效率

----------------------------------------------------------------------

先一次性生成一個csv文件
再用split分割文件

--------------------------------------------------------

完全贊同樓上說的。

關於性能問題,用oracle spool出80萬行紀錄是非常快的,我剛試了一下,再hp-ux下,spool出某表中100萬紀錄(2列)耗時大約2分鐘,輸出文件80m, 用split命令分割為每個4000行的文件耗時數秒而已。 下附測試代碼:

/* sql file: spool_test.sql */
set pages 0
set head off
set echo off
set feedback off
spool spool_text.csv
select col1, col2 from my_table where rownum<1000000;
spool off
exit

## shell script to spool out:
sqlplus -s user/password @spool_test.sql > /dev/null

## split file:
split -l 4000 spool_text.csv splited


--------------------------------------------------------

export.sh

#Generate the sql language
echo "SET HEADING OFF;">${SqlDir}/select_log.sql
echo "SET FEEDBACK OFF;">>${SqlDir}/select_log.sql
echo "SET LINESIZE 10000;">>${SqlDir}/select_log.sql
echo "SPOOL ${SqlDir}/EXPORT_ALL.CSV;" >> ${SqlDir}/select_log.sql
echo "SELECT SALESMAN_ID||‘,‘||">>${SqlDir}/select_log.sql
echo "SALESMAN_NAME||‘,‘||">>${SqlDir}/select_log.sql
echo "SALES_AMOUNT||‘,‘||">>${SqlDir}/select_log.sql
echo "SALES_DATE from sales_range;">>${SqlDir}/select_log.sql
echo "SPOOL OFF;" >> ${SqlDir}/select_log.sql
echo exit | ${ORACLE_HOME}/bin/sqlplus -s omc_sbardz812/omc_sbardz812 @${SqlDir}
/select_log.sql >/dev/null

split -l 4000 -a 5 ${SqlDir}/EXPORT_ALL.CSV log_20060606_
=============================================================

以上是我的腳本,80w數據我用了3個多小時還沒完呢。有問題嗎?
另外,很重要的一點,split後,再不是csv後綴了。看來還得文件遍歷,然後一個一個的mv 成csv文件。



--------------------------------------------------------

先整個導出罷,然後在處理

--------------------------------------------------------

你的代碼看起來沒有問題,但80萬條記錄導3小時沒完成很難讓人理解。

你用sqlplus做一下測試,比如導出10000條記錄需要多少時間,如果確實很慢,那可能是連接太慢(網絡速度?)。

--------------------------------------------------------

導出為csv文件很快,就幾分鐘而已,但是split要花3個小時,共250個文件,每個文件4000行。我的機器是SUN Blade 150,還有我在server上運行的,不存在網絡速度的問題。

--------------------------------------------------------

根據需要導出的列,單獨建個臨時表,比如:create table sales_range_tmp as select salesman_id,salesman_name,sales_amount,sales_date from sales;
再利用腳本導出來,看看速度應該有所提高。不過有一點必須明白,全掃描8w的表數據肯定不是幾分鐘可以完成的,何況要寫成物理文件。


--------------------------------------------------------

KingSunSha(弱水三千),我用spool導出的文件大小為9G(8900828448byte on solaris),而你的才80M

--------------------------------------------------------

SELECT 中不要拼接字符串,非常影響速度

--------------------------------------------------------

大家還有好的辦法嗎?

--------------------------------------------------------

9GB = 9,216 MB = 9,437,184 KB = 9,663,676,416 Bytes
800,000 records
size of each record (line) = 9GB/800,000 = 12,079 Bytes

select 中只有 4 列(SALESMAN_ID, SALESMAN_NAME, SALES_AMOUNT, SALES_DATE
),你覺得每行紀錄占12KB合理嗎?

--------------------------------------------------------

問題是你在sqlplus中用了set linesize=100000,所以每行都會spool出100000bytes。
解決這個問題很簡單,在spool開始之前加上兩行set命令

set trimspool on
set termout off

第一個set是指定trim spool出的每行在行末的空格
第二個set是指定只spool而不回顯,所以在運行sqlplus的時候不需要 >/dev/null。


--------------------------------------------------------

非常感謝KingSunSha(弱水三千),現在我把linesize改為100,非常快,2分鐘就完成了。太好了。不過還有一個問題,導出的文件,每隔13行就會自動設置一個空行,能把這個去掉嗎?因為我導出的文件會被我的程序打開的。

--------------------------------------------------------

just add
set pagesize 0
before spool to suppress all headings, page breaks, titles, the initial blank line, and other formatting information.


--------------------------------------------------------

just add
set pagesize 0
before spool to suppress all headings, page breaks, titles, the initial blank line, and other formatting information.

--------------------------------------------------------

非常感謝KingSunSha(弱水三千),搞定了,貼出來吧,共享!

echo "SET HEADING OFF;">${SqlDir}/select_log.sql
echo "SET FEEDBACK OFF;">>${SqlDir}/select_log.sql
echo "SET LINESIZE 500;">>${SqlDir}/select_log.sql
echo "SET trimspool on;">>${SqlDir}/select_log.sql
echo "SET termout off;" >>${SqlDir}/select_log.sql
echo "SET NEWPAGE NONE;" >>${SqlDir}/select_log.sql
echo "SPOOL ${SqlDir}/EXPORT_ALL.CSV;" >> ${SqlDir}/select_log.sql
echo "SELECT SALESMAN_ID||‘,‘||">>${SqlDir}/select_log.sql
echo "SALESMAN_NAME||‘,‘||">>${SqlDir}/select_log.sql
echo "SALES_AMOUNT||‘,‘||">>${SqlDir}/select_log.sql
echo "SALES_DATE from sales_range;">>${SqlDir}/select_log.sql
echo "SPOOL OFF;" >> ${SqlDir}/select_log.sql
echo exit | ${ORACLE_HOME}/bin/sqlplus -s user/pwd @${SqlDir}/select_log.sql

split -l 4000 -a 3 ${SqlDir}/EXPORT_ALL.CSV log_20060606_

#mv these splitted file to be csv file
for file in $(ls ./)
do
echo $file | grep log_20060606_ > /dev/null
status=$?
if [ $status -eq 0 ]; then
mv $file $file.csv
fi
status=1
done

80萬10分鐘就可以搞定了。

ksh可以執行,由於有這句:$(ls ./),sh不支持。

--------------------------------------------------------

謝謝大家!

http://blog.csdn.net/studyvcmfc/article/details/7047986

oracle導出多CSV文件的靠譜的