外部排序優化

壹頁書發表於2014-05-29
優化外部排序
主要步驟重新拆分如下
第一階段
1.將未排序的大檔案切分(spilterReceiver)
2.一個執行緒池專門接收byte[],並將其轉化為long[] (prepareReceiver)
3.一個執行緒池專門排序long[] (sortReceiver)
4.一個執行緒池專門將已經有序的long[]寫入檔案 (writerReceiver)

這個過程直接寫long型別的數字到檔案,因為寫入文字佔用IO資源比直接寫入long型數字要多。

第二階段
1.一個執行緒用於歸併排序,將結果寫入緩衝區 (mergerReceiver)
2.如果緩衝區快滿了,就將其交給一個執行緒池用於寫入最終的檔案。 (mergerReceiver)

優化的重點是平衡CPU,記憶體和硬碟的資源使用。

每個電腦的配置不同,都需要進行不同的調整,才能達到最優化的效果。
單位的電腦是i5的CPU,8G記憶體,7200轉硬碟。
我使用的虛擬機器分配了2個核心,4G記憶體。
跑這個程式大致需要200s左右。
因為第二階段的第一個步驟是非常消耗CPU資源的,單位電腦CPU主頻很高,所以不會成為瓶頸。

而家裡的電腦,應該配置更接近吳老師做實驗的配置。主頻比較低,32位系統,4G記憶體。
這個配置明顯CPU成為瓶頸
在第一個階段,切分出來的檔案,由於CPU不能及時排序並輸出,經常導致OOM
只能在切分一個檔案出來之後,讓切分執行緒sleep一段時間,大量測試得到的結果是這個執行緒至少sleep2500毫秒才能不導致OOM。
也就是說,CPU運算的速度跟不上IO的速度。後來想到一個方法,加大分片。原來4G檔案使用15個分片,現在使用30個分片。資料快入快出,這樣可以避免OOM。至於這個分片的數字,恐怕每個機器都需要實際的測試。
另外在第二階段,也出現了CPU拖累IO,導致效能下降。
因為歸併的時候,需要大量運算各個分片中最小的資料,經常看到計算50M資料,CPU需要2s,而寫入一般1s就可以完成。
而這個過程是單執行緒的,CPU的主頻直接決定了外部排序的總體時間。


  1. import java.io.BufferedInputStream;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.IOException;
  5. import java.io.RandomAccessFile;
  6. import java.nio.ByteBuffer;
  7. import java.nio.MappedByteBuffer;
  8. import java.nio.channels.FileChannel;
  9. import java.nio.channels.FileChannel.MapMode;
  10. import java.util.ArrayList;
  11. import java.util.Arrays;
  12. import java.util.Collections;
  13. import java.util.List;
  14. import java.util.concurrent.BrokenBarrierException;
  15. import java.util.concurrent.CyclicBarrier;
  16. import java.util.concurrent.ExecutorService;
  17. import java.util.concurrent.Executors;

  18. public class Controller {
  19.     public static void main(String[] args) throws IOException {
  20.         new Controller().action(new File("/home/lihuilin/桌面/t.txt"), 30, "/home/lihuilin/桌面/");

  21.     }

  22.     public void action(File file, int pieces, String outDir) throws IOException {
  23.         Invoker invoker = new Invoker(pieces);
  24.         List<Command> commandList = blocking(file, pieces, outDir);
  25.         for (Command command : commandList) {
  26.             command.setInvoker(invoker);
  27.             invoker.executeCommand(command);
  28.         }
  29.     }

  30.     private List<Command> blocking(File file, int pieces, String outDir) throws IOException {
  31.         List<Command> result = new ArrayList<Command>();
  32.         List<Long> list = new ArrayList<Long>();
  33.         list.add(-1L);
  34.         long length = file.length();
  35.         long step = length / pieces;
  36.         long index = 0;
  37.         for (int i = 0; i < pieces; i++) {
  38.             BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
  39.             if (index + step < length) {
  40.                 index = index + step;
  41.                 in.skip(index);
  42.                 while (in.read() != 10) {
  43.                     index = index + 1;
  44.                 }
  45.                 list.add(index);
  46.                 index++;
  47.             }
  48.             in.close();
  49.         }
  50.         list.add(length - 1);
  51.         for (int i = 0; i < list.size() - 1; i++) {
  52.             long skipSize = list.get(i) + 1;
  53.             long l = list.get(i + 1) - list.get(i);
  54.             result.add(new SpilterCommand(file, skipSize, l, outDir));
  55.         }
  56.         return result;
  57.     }

  58. }

  59. interface Command extends Comparable<Command> {
  60.     public void setInvoker(Invoker invoker);

  61.     public void setReceiver(Receiver receiver);

  62.     public void execute() throws IOException;

  63.     public long getSkipSize();

  64.     public int getLength();

  65.     public String getOutDir();

  66.     public File getSourceFile();

  67.     public Invoker getInvoker();

  68.     public void clear();

  69.     public File getOutFile();

  70.     public File getTargetFile();
  71. }

  72. class Invoker {
  73.     private Receiver sortReceiver;
  74.     private Receiver spilterReceiver;
  75.     private Receiver writerReceiver;
  76.     private Receiver prepareReceiver;
  77.     private Receiver mergerReceiver;

  78.     public Invoker(int pieces) {
  79.         writerReceiver = new WriterReceiver(pieces);
  80.         spilterReceiver = new SpilterReceiver();
  81.         sortReceiver = new SorterReceiver();
  82.         prepareReceiver = new PrepareReceiver();
  83.         mergerReceiver = new MergerReceiver();
  84.     }

  85.     public void executeCommand(Command command) {
  86.         try {
  87.             if (command instanceof SpilterCommand) {
  88.                 spilterReceiver.action(command);
  89.             } else if (command instanceof PrepareCommand) {
  90.                 prepareReceiver.action(command);
  91.             } else if (command instanceof SortCommand) {
  92.                 sortReceiver.action(command);
  93.             } else if (command instanceof WriterCommand) {
  94.                 writerReceiver.action(command);
  95.             } else if (command instanceof MergeCommand) {
  96.                 mergerReceiver.action(command);
  97.             } else if (command instanceof KillCommand) {
  98.                 writerReceiver.shutdown();
  99.                 spilterReceiver.shutdown();
  100.                 sortReceiver.shutdown();
  101.                 prepareReceiver.shutdown();
  102.                 mergerReceiver.shutdown();
  103.             }
  104.         } catch (IOException ex) {
  105.             ex.printStackTrace();
  106.         }
  107.     }
  108. }

  109. class SpilterCommand extends AbstractCommand {

  110.     public SpilterCommand(File sourceFile, long skipSize, long length, String outDir) {
  111.         super(sourceFile, skipSize, length, outDir);
  112.     }

  113.     @Override
  114.     public void clear() {

  115.     }

  116. }

  117. abstract class AbstractCommand implements Command {
  118.     private Invoker invoker = null;
  119.     private Receiver receiver = null;
  120.     private long skipSize = 0L;
  121.     private int length = 0;
  122.     private String outDir = null;
  123.     private File sourceFile;
  124.     private File outFile = null;
  125.     public static final long START = System.currentTimeMillis();
  126.     private static int FLAG = 0;
  127.     private File targetFile = null;

  128.     private synchronized int getFlag() {
  129.         return FLAG++;
  130.     }

  131.     public AbstractCommand(Command command) {
  132.         this(command.getSourceFile(), command.getSkipSize(), command.getLength(), command.getOutDir());
  133.         this.invoker = command.getInvoker();
  134.         if (command.getOutFile() != null) {
  135.             this.outFile = command.getOutFile();
  136.         } else {
  137.             this.outFile = new File(this.outDir + getFlag() + ".temp");
  138.         }
  139.     }

  140.     public AbstractCommand(File sourceFile, long skipSize, long length, String outDir) {
  141.         if (length > Integer.MAX_VALUE) {
  142.             throw new RuntimeException("長度溢位");
  143.         }
  144.         this.skipSize = skipSize;
  145.         this.length = (int) length;
  146.         this.outDir = outDir;
  147.         this.sourceFile = sourceFile;
  148.         this.targetFile = new File(outDir + "result.temp");
  149.     }

  150.     public void setInvoker(Invoker invoker) {
  151.         this.invoker = invoker;
  152.     }

  153.     public void setReceiver(Receiver receiver) {
  154.         this.receiver = receiver;
  155.     }

  156.     public long getSkipSize() {
  157.         return skipSize;
  158.     }

  159.     public int getLength() {
  160.         return length;
  161.     }

  162.     public String getOutDir() {
  163.         return outDir;
  164.     }

  165.     public File getSourceFile() {
  166.         return sourceFile;
  167.     }

  168.     @Override
  169.     public String toString() {
  170.         return "Command [skipSize=" + skipSize + ", length=" + length + "]";
  171.     }

  172.     public void execute() throws IOException {
  173.         this.receiver.action(this);
  174.     }

  175.     public Invoker getInvoker() {
  176.         return invoker;
  177.     }

  178.     public File getOutFile() {
  179.         return this.outFile;
  180.     }

  181.     public File getTargetFile() {
  182.         return this.targetFile;
  183.     }

  184.     @Override
  185.     public int compareTo(Command o) {
  186.         if (this.skipSize < o.getSkipSize()) {
  187.             return -1;
  188.         }
  189.         return 1;
  190.     }
  191. }

  192. interface Receiver {
  193.     public void action(Command command) throws IOException;

  194.     public void shutdown();
  195. }

  196. class PrepareReceiver implements Receiver {
  197.     private ExecutorService prepareThreadPool;

  198.     public PrepareReceiver() {
  199.         prepareThreadPool = Executors.newFixedThreadPool(4);
  200.     }

  201.     @Override
  202.     public void action(final Command command) throws IOException {
  203.         prepareThreadPool.submit(new Runnable() {

  204.             @Override
  205.             public void run() {
  206.                 System.out.println("\t整理資料:" + command);
  207.                 long start = System.currentTimeMillis();

  208.                 byte[] data = ((PrepareCommand) command).getData();
  209.                 long[] result = new long[getObjectSize(data)];
  210.                 int resultIndex = 0;
  211.                 int index = 0;
  212.                 int first = 0;
  213.                 while (index < data.length) {
  214.                     if (data[index] == 10) {
  215.                         byte[] tmpData = Arrays.copyOfRange(data, first, index);
  216.                         String str = new String(tmpData);
  217.                         result[resultIndex] = Long.valueOf(str);
  218.                         resultIndex++;
  219.                         first = index + 1;
  220.                     }

  221.                     index++;
  222.                 }
  223.                 command.getInvoker().executeCommand(new SortCommand(command, result));

  224.                 result = null;
  225.                 data = null;
  226.                 command.clear();

  227.                 long end = System.currentTimeMillis();
  228.                 System.out.println("\t結束整理資料:" + command + ",用時:" + (end - start) / 1000);
  229.             }

  230.         });

  231.     }

  232.     private int getObjectSize(byte[] data) {
  233.         int size = 0;
  234.         for (byte b : data) {
  235.             if (b == 10) {
  236.                 size++;
  237.             }
  238.         }
  239.         return size;
  240.     }

  241.     @Override
  242.     public void shutdown() {
  243.         this.prepareThreadPool.shutdown();
  244.     }

  245. }

  246. class PrepareCommand extends AbstractCommand {

  247.     private byte[] data;

  248.     public PrepareCommand(Command command, byte[] data) {
  249.         super(command);
  250.         this.data = data;
  251.     }

  252.     public byte[] getData() {
  253.         return this.data;
  254.     }

  255.     @Override
  256.     public void clear() {
  257.         this.data = null;
  258.     }
  259. }

  260. class SpilterReceiver implements Receiver {
  261.     @Override
  262.     public void action(final Command command) throws IOException {
  263.         try {
  264.             System.out.println("開始讀入:" + command);
  265.             long start = System.currentTimeMillis();
  266.             FileChannel in = new RandomAccessFile(command.getSourceFile(), "r").getChannel();
  267.             MappedByteBuffer inBuffer = in.map(MapMode.READ_ONLY, command.getSkipSize(), command.getLength());
  268.             byte[] data = new byte[inBuffer.limit()];
  269.             inBuffer.get(data);
  270.             command.getInvoker().executeCommand(new PrepareCommand(command, data));

  271.             data = null;
  272.             in.close();
  273.             command.clear();

  274.             long end = System.currentTimeMillis();
  275.             System.out.println("結束記憶體讀入:" + (end - start) / 1000 + "s");

  276.         } catch (IOException e) {
  277.             e.printStackTrace();
  278.         }
  279.     }

  280.     @Override
  281.     public void shutdown() {
  282.     }
  283. }

  284. class MergeCommand extends AbstractCommand {
  285.     private List<Command> commandList = null;

  286.     public MergeCommand(List<Command> commandList) {
  287.         super(commandList.get(0));
  288.         this.commandList = commandList;
  289.     }

  290.     @Override
  291.     public void clear() {

  292.     }

  293.     public List<Command> getCommandList() {
  294.         return this.commandList;
  295.     }
  296. }

  297. class KillCommand extends AbstractCommand {

  298.     public KillCommand(Command command) {
  299.         super(command);
  300.     }

  301.     @Override
  302.     public void clear() {

  303.     }

  304. }

  305. class MergerReceiver implements Receiver {
  306.     private ExecutorService mergerThreadPool = Executors.newFixedThreadPool(4);
  307.     private List<Worker> workerList = new ArrayList<Worker>();
  308.     private ByteBuffer bb = null;

  309.     @Override
  310.     public void action(final Command command) throws IOException {
  311.         bb = ByteBuffer.allocate(50 * 1024 * 1024);
  312.         List<Command> list = ((MergeCommand) command).getCommandList();
  313.         for (Command historyCommand : list) {
  314.             Worker worker = new Worker(historyCommand.getOutFile(), workerList);
  315.             workerList.add(worker);
  316.         }

  317.         System.out.println("讀取佇列,寫入目標檔案");
  318.         long start = System.currentTimeMillis();
  319.         RandomAccessFile targetFile = new RandomAccessFile(command.getTargetFile(), "rw");
  320.         FileChannel channel = targetFile.getChannel();
  321.         MappedByteBuffer out = null;
  322.         long index = 0L;
  323.         while (workerList.size() != 0) {
  324.             Worker worker = Collections.min(workerList);
  325.             Long data = worker.poll();
  326.             if (data == null) {
  327.                 workerList.remove(worker);
  328.             } else {

  329.                 bb.put((data + "\n").getBytes());

  330.                 if (bb.position() > 49 * 1024 * 1024) {
  331.                     long end = System.currentTimeMillis();
  332.                     System.out.println("歸併用時:" + (end - start)/1000 + "s");
  333.                     start = System.currentTimeMillis();
  334.                     bb.flip();
  335.                     long temp = bb.limit();
  336.                     MutiWriter writer = new MutiWriter(channel, bb, index);
  337.                     mergerThreadPool.submit(writer);
  338.                     index = index + temp;
  339.                     bb = ByteBuffer.allocate(50 * 1024 * 1024);
  340.                 }

  341.             }
  342.         }

  343.         bb.flip();

  344.         out = channel.map(MapMode.READ_WRITE, index, bb.limit());
  345.         int i = bb.limit();
  346.         while (i > .0) {
  347.             out.put(bb.get());
  348.             i--;
  349.         }
  350.         out.force();
  351.         channel.close();
  352.         targetFile.close();

  353.         KillCommand killCommand = new KillCommand(command);
  354.         command.getInvoker().executeCommand(killCommand);

  355.         long end = System.currentTimeMillis();
  356.         System.out.println("外部排序總用時:" + (end - AbstractCommand.START) / 1000);

  357.     }

  358.     private class MutiWriter implements Runnable {
  359.         private ByteBuffer buffer;
  360.         private MappedByteBuffer out = null;

  361.         public MutiWriter(FileChannel channel, ByteBuffer buffer, long index) {
  362.             this.buffer = buffer;
  363.             try {
  364.                 out = channel.map(MapMode.READ_WRITE, index, buffer.limit());
  365.             } catch (IOException e) {
  366.                 e.printStackTrace();
  367.             }
  368.         }

  369.         @Override
  370.         public void run() {
  371.             long a1 = System.currentTimeMillis();
  372.             int i = buffer.limit();
  373.             while (i > 0) {
  374.                 out.put(buffer.get());
  375.                 i--;
  376.             }
  377.             out.force();
  378.             out = null;
  379.             long a2 = System.currentTimeMillis();
  380.             System.out.println("記憶體對映寫入:" + (a2 - a1) / 1000 + "s");
  381.         }

  382.     }

  383.     @Override
  384.     public void shutdown() {
  385.         mergerThreadPool.shutdown();
  386.     }

  387.     private class Worker implements Comparable<Worker> {
  388.         private long data;
  389.         private MappedByteBuffer buffer = null;
  390.         private List<Worker> workerList = null;
  391.         private boolean eof = false;

  392.         Worker(File file, List<Worker> workerList) {
  393.             try {
  394.                 RandomAccessFile rFile = new RandomAccessFile(file, "r");
  395.                 FileChannel channel = rFile.getChannel();
  396.                 buffer = channel.map(MapMode.READ_ONLY, 0, channel.size());

  397.                 this.workerList = workerList;
  398.                 data = buffer.getLong();

  399.                 rFile.close();
  400.                 channel.close();

  401.             } catch (IOException e) {
  402.                 // TODO Auto-generated catch block
  403.                 e.printStackTrace();
  404.             }
  405.         }

  406.         public long peek() {
  407.             return data;
  408.         }

  409.         public Long poll() {
  410.             long result = data;
  411.             if (buffer.position() != buffer.limit()) {
  412.                 data = buffer.getLong();
  413.             } else {
  414.                 if (eof == false) {
  415.                     eof = true;
  416.                 } else {
  417.                     return null;
  418.                 }
  419.             }

  420.             return result;
  421.         }

  422.         @Override
  423.         public int compareTo(Worker o) {
  424.             if (this.peek() > o.peek()) {
  425.                 return 1;
  426.             } else if (this.peek() < o.peek()) {
  427.                 return -1;
  428.             } else {
  429.                 return 0;
  430.             }
  431.         }
  432.     }

  433. }

  434. class WriterReceiver implements Receiver {
  435.     private ExecutorService writeThreadPool = null;;
  436.     private CyclicBarrier barrier = null;
  437.     private List<Command> commandList = new ArrayList<Command>();

  438.     public WriterReceiver(int pieces) {
  439.         writeThreadPool = Executors.newFixedThreadPool(pieces + 2);
  440.         barrier = new CyclicBarrier(pieces, new Runnable() {

  441.             @Override
  442.             public void run() {
  443.                 long end = System.currentTimeMillis();
  444.                 System.out.println("合併之前總用時:" + (end - AbstractCommand.START) / 1000);

  445.                 MergeCommand command = new MergeCommand(WriterReceiver.this.commandList);
  446.                 command.getInvoker().executeCommand(command);

  447.             }
  448.         });

  449.     }

  450.     @Override
  451.     public void action(final Command command) {
  452.         writeThreadPool.submit(new Runnable() {

  453.             @Override
  454.             public void run() {
  455.                 long[] data = ((WriterCommand) command).getData();

  456.                 try {
  457.                     System.out.println("\t\t\t開始寫入:" + command);
  458.                     long start = System.currentTimeMillis();
  459.                     File outfile = command.getOutFile();
  460.                     FileChannel channel = new RandomAccessFile(outfile, "rw").getChannel();
  461.                     MappedByteBuffer buffer = channel.map(MapMode.READ_WRITE, 0, data.length * 8);
  462.                     for (int i = 0; i < data.length; i++) {
  463.                         buffer.putLong(data[i]);
  464.                     }
  465.                     buffer.force();
  466.                     WriterReceiver.this.commandList.add(command);
  467.                     long end = System.currentTimeMillis();
  468.                     System.out.println("\t\t\t結束寫入:" + command + ",用時:" + (end - start) / 1000);

  469.                     command.clear();
  470.                     data = null;
  471.                     channel.close();
  472.                     buffer = null;

  473.                     barrier.await();
  474.                 } catch (IOException ex) {
  475.                     ex.printStackTrace();
  476.                 } catch (InterruptedException e) {
  477.                     e.printStackTrace();
  478.                 } catch (BrokenBarrierException e) {
  479.                     e.printStackTrace();
  480.                 }
  481.             }
  482.         });
  483.     }

  484.     @Override
  485.     public void shutdown() {
  486.         writeThreadPool.shutdown();
  487.     }
  488. }

  489. class SortCommand extends AbstractCommand {
  490.     private long[] data = null;

  491.     public SortCommand(Command command, long[] data) {
  492.         super(command);
  493.         this.data = data;
  494.     }

  495.     public long[] getData() {
  496.         return this.data;
  497.     }

  498.     @Override
  499.     public void clear() {
  500.         this.data = null;
  501.     }

  502. }

  503. class SorterReceiver implements Receiver {
  504.     private ExecutorService sortThreadPool = Executors.newFixedThreadPool(4);

  505.     public void action(final Command command) {
  506.         sortThreadPool.submit(new Runnable() {

  507.             @Override
  508.             public void run() {
  509.                 System.out.println("\t\t開始排序:" + command);
  510.                 long start = System.currentTimeMillis();

  511.                 long[] data = ((SortCommand) command).getData();
  512.                 Arrays.sort(data);

  513.                 command.getInvoker().executeCommand(new WriterCommand(command, data));

  514.                 data = null;
  515.                 command.clear();

  516.                 long end = System.currentTimeMillis();
  517.                 System.out.println("\t\t結束排序:" + command + ",用時:" + (end - start) / 1000);

  518.             }

  519.         });

  520.     }

  521.     @Override
  522.     public void shutdown() {
  523.         sortThreadPool.shutdown();
  524.     }
  525. }

  526. class WriterCommand extends AbstractCommand {
  527.     private long[] data;

  528.     public WriterCommand(Command command, long[] data) {
  529.         super(command);
  530.         this.data = data;
  531.     }

  532.     public long[] getData() {
  533.         return this.data;
  534.     }

  535.     @Override
  536.     public void clear() {
  537.         this.data = null;
  538.     }

  539. }
最近真的很忙,我這一個單執行緒的CPU居然都跑出了雙核的感覺。
我感覺優化就是找到慢的地方,看看是不是有無效的操作,如果都是有效運算,就只能想辦法使用多執行緒,使壓力分散在多個核心上。
之前吳老師說他用的是直接緩衝區+通道 IO的方式。自己寫程式將long直接轉化為byte。
這個優化的方式我試了一下,不能應用在我的場景。
他的本意是減少GC,但是在我的場景,這種方式更加劇了CPU的爭用。
優化的本質應該是平衡資源

程式日誌,相比最初的版本,效能提升了50s
因為將切分檔案,byte陣列轉為long陣列拆分為了兩個操作,並且使用了多執行緒處理。
  1. 開始讀入:Command [skipSize=0, length=135863265]
  2. 結束記憶體讀入:3s
  3. 整理資料:Command [skipSize=0, length=135863265]
  4. 開始讀入:Command [skipSize=135863265, length=135863254]
  5. 結束整理資料:Command [skipSize=0, length=135863265],用時:4
  6. 開始排序:Command [skipSize=0, length=135863265]
  7. 結束記憶體讀入:4s
  8. 開始讀入:Command [skipSize=271726519, length=135863267]
  9. 整理資料:Command [skipSize=135863265, length=135863254]
  10. 結束排序:Command [skipSize=0, length=135863265],用時:2
  11. 開始寫入:Command [skipSize=0, length=135863265]
  12. 結束記憶體讀入:3s
  13. 開始讀入:Command [skipSize=407589786, length=135863268]
  14. 整理資料:Command [skipSize=271726519, length=135863267]
  15. 結束寫入:Command [skipSize=0, length=135863265],用時:2
  16. 結束整理資料:Command [skipSize=135863265, length=135863254],用時:5
  17. 開始排序:Command [skipSize=135863265, length=135863254]
  18. 結束排序:Command [skipSize=135863265, length=135863254],用時:1
  19. 開始寫入:Command [skipSize=135863265, length=135863254]
  20. 結束整理資料:Command [skipSize=271726519, length=135863267],用時:4
  21. 開始排序:Command [skipSize=271726519, length=135863267]
  22. 結束排序:Command [skipSize=271726519, length=135863267],用時:1
  23. 開始寫入:Command [skipSize=271726519, length=135863267]
  24. 結束寫入:Command [skipSize=135863265, length=135863254],用時:6
  25. 結束寫入:Command [skipSize=271726519, length=135863267],用時:4
  26. 結束記憶體讀入:11s
  27. 整理資料:Command [skipSize=407589786, length=135863268]
  28. 開始讀入:Command [skipSize=543453054, length=135863264]
  29. 結束整理資料:Command [skipSize=407589786, length=135863268],用時:3
  30. 開始排序:Command [skipSize=407589786, length=135863268]
  31. 結束記憶體讀入:4s
  32. 開始讀入:Command [skipSize=679316318, length=135863268]
  33. 整理資料:Command [skipSize=543453054, length=135863264]
  34. 結束排序:Command [skipSize=407589786, length=135863268],用時:1
  35. 開始寫入:Command [skipSize=407589786, length=135863268]
  36. 結束寫入:Command [skipSize=407589786, length=135863268],用時:1
  37. 結束整理資料:Command [skipSize=543453054, length=135863264],用時:3
  38. 開始排序:Command [skipSize=543453054, length=135863264]
  39. 結束排序:Command [skipSize=543453054, length=135863264],用時:1
  40. 開始寫入:Command [skipSize=543453054, length=135863264]
  41. 結束寫入:Command [skipSize=543453054, length=135863264],用時:1
  42. 結束記憶體讀入:7s
  43. 整理資料:Command [skipSize=679316318, length=135863268]
  44. 開始讀入:Command [skipSize=815179586, length=135863264]
  45. 結束記憶體讀入:3s
  46. 開始讀入:Command [skipSize=951042850, length=135863270]
  47. 整理資料:Command [skipSize=815179586, length=135863264]
  48. 開始排序:Command [skipSize=679316318, length=135863268]
  49. 結束整理資料:Command [skipSize=679316318, length=135863268],用時:3
  50. 結束排序:Command [skipSize=679316318, length=135863268],用時:2
  51. 開始寫入:Command [skipSize=679316318, length=135863268]
  52. 結束整理資料:Command [skipSize=815179586, length=135863264],用時:4
  53. 開始排序:Command [skipSize=815179586, length=135863264]
  54. 結束寫入:Command [skipSize=679316318, length=135863268],用時:2
  55. 結束記憶體讀入:5s
  56. 整理資料:Command [skipSize=951042850, length=135863270]
  57. 開始讀入:Command [skipSize=1086906120, length=135863262]
  58. 結束排序:Command [skipSize=815179586, length=135863264],用時:1
  59. 開始寫入:Command [skipSize=815179586, length=135863264]
  60. 結束寫入:Command [skipSize=815179586, length=135863264],用時:1
  61. 整理資料:Command [skipSize=1086906120, length=135863262]
  62. 結束記憶體讀入:3s
  63. 開始讀入:Command [skipSize=1222769382, length=135863265]
  64. 開始排序:Command [skipSize=951042850, length=135863270]
  65. 結束整理資料:Command [skipSize=951042850, length=135863270],用時:4
  66. 結束記憶體讀入:3s
  67. 開始讀入:Command [skipSize=1358632647, length=135863256]
  68. 整理資料:Command [skipSize=1222769382, length=135863265]
  69. 結束排序:Command [skipSize=951042850, length=135863270],用時:2
  70. 開始寫入:Command [skipSize=951042850, length=135863270]
  71. 結束寫入:Command [skipSize=951042850, length=135863270],用時:1
  72. 結束整理資料:Command [skipSize=1086906120, length=135863262],用時:5
  73. 開始排序:Command [skipSize=1086906120, length=135863262]
  74. 結束排序:Command [skipSize=1086906120, length=135863262],用時:1
  75. 開始寫入:Command [skipSize=1086906120, length=135863262]
  76. 結束記憶體讀入:4s
  77. 整理資料:Command [skipSize=1358632647, length=135863256]
  78. 開始讀入:Command [skipSize=1494495903, length=135863268]
  79. 結束寫入:Command [skipSize=1086906120, length=135863262],用時:1
  80. 開始排序:Command [skipSize=1222769382, length=135863265]
  81. 結束整理資料:Command [skipSize=1222769382, length=135863265],用時:6
  82. 結束排序:Command [skipSize=1222769382, length=135863265],用時:1
  83. 開始寫入:Command [skipSize=1222769382, length=135863265]
  84. 整理資料:Command [skipSize=1494495903, length=135863268]
  85. 結束記憶體讀入:4s
  86. 開始讀入:Command [skipSize=1630359171, length=135863255]
  87. 開始排序:Command [skipSize=1358632647, length=135863256]
  88. 結束整理資料:Command [skipSize=1358632647, length=135863256],用時:5
  89. 結束寫入:Command [skipSize=1222769382, length=135863265],用時:1
  90. 結束排序:Command [skipSize=1358632647, length=135863256],用時:1
  91. 開始寫入:Command [skipSize=1358632647, length=135863256]
  92. 結束整理資料:Command [skipSize=1494495903, length=135863268],用時:3
  93. 結束寫入:Command [skipSize=1358632647, length=135863256],用時:2
  94. 開始排序:Command [skipSize=1494495903, length=135863268]
  95. 結束記憶體讀入:4s
  96. 整理資料:Command [skipSize=1630359171, length=135863255]
  97. 開始讀入:Command [skipSize=1766222426, length=135863271]
  98. 結束排序:Command [skipSize=1494495903, length=135863268],用時:1
  99. 開始寫入:Command [skipSize=1494495903, length=135863268]
  100. 結束寫入:Command [skipSize=1494495903, length=135863268],用時:1
  101. 結束整理資料:Command [skipSize=1630359171, length=135863255],用時:3
  102. 開始排序:Command [skipSize=1630359171, length=135863255]
  103. 整理資料:Command [skipSize=1766222426, length=135863271]
  104. 結束記憶體讀入:4s
  105. 開始讀入:Command [skipSize=1902085697, length=135863258]
  106. 結束排序:Command [skipSize=1630359171, length=135863255],用時:2
  107. 開始寫入:Command [skipSize=1630359171, length=135863255]
  108. 結束寫入:Command [skipSize=1630359171, length=135863255],用時:1
  109. 結束整理資料:Command [skipSize=1766222426, length=135863271],用時:3
  110. 開始排序:Command [skipSize=1766222426, length=135863271]
  111. 整理資料:Command [skipSize=1902085697, length=135863258]
  112. 結束記憶體讀入:4s
  113. 開始讀入:Command [skipSize=2037948955, length=135863254]
  114. 結束排序:Command [skipSize=1766222426, length=135863271],用時:1
  115. 開始寫入:Command [skipSize=1766222426, length=135863271]
  116. 結束寫入:Command [skipSize=1766222426, length=135863271],用時:1
  117. 結束整理資料:Command [skipSize=1902085697, length=135863258],用時:3
  118. 開始排序:Command [skipSize=1902085697, length=135863258]
  119. 整理資料:Command [skipSize=2037948955, length=135863254]
  120. 結束記憶體讀入:4s
  121. 開始讀入:Command [skipSize=2173812209, length=135863259]
  122. 結束排序:Command [skipSize=1902085697, length=135863258],用時:2
  123. 開始寫入:Command [skipSize=1902085697, length=135863258]
  124. 結束寫入:Command [skipSize=1902085697, length=135863258],用時:1
  125. 結束整理資料:Command [skipSize=2037948955, length=135863254],用時:3
  126. 開始排序:Command [skipSize=2037948955, length=135863254]
  127. 結束記憶體讀入:4s
  128. 整理資料:Command [skipSize=2173812209, length=135863259]
  129. 開始讀入:Command [skipSize=2309675468, length=135863260]
  130. 結束排序:Command [skipSize=2037948955, length=135863254],用時:2
  131. 開始寫入:Command [skipSize=2037948955, length=135863254]
  132. 結束整理資料:Command [skipSize=2173812209, length=135863259],用時:3
  133. 開始排序:Command [skipSize=2173812209, length=135863259]
  134. 結束記憶體讀入:4s
  135. 整理資料:Command [skipSize=2309675468, length=135863260]
  136. 開始讀入:Command [skipSize=2445538728, length=135863266]
  137. 結束寫入:Command [skipSize=2037948955, length=135863254],用時:2
  138. 結束排序:Command [skipSize=2173812209, length=135863259],用時:2
  139. 開始寫入:Command [skipSize=2173812209, length=135863259]
  140. 結束寫入:Command [skipSize=2173812209, length=135863259],用時:1
  141. 結束整理資料:Command [skipSize=2309675468, length=135863260],用時:3
  142. 開始排序:Command [skipSize=2309675468, length=135863260]
  143. 整理資料:Command [skipSize=2445538728, length=135863266]
  144. 結束記憶體讀入:4s
  145. 開始讀入:Command [skipSize=2581401994, length=135863268]
  146. 結束排序:Command [skipSize=2309675468, length=135863260],用時:2
  147. 開始寫入:Command [skipSize=2309675468, length=135863260]
  148. 結束寫入:Command [skipSize=2309675468, length=135863260],用時:1
  149. 結束整理資料:Command [skipSize=2445538728, length=135863266],用時:4
  150. 開始排序:Command [skipSize=2445538728, length=135863266]
  151. 結束記憶體讀入:4s
  152. 整理資料:Command [skipSize=2581401994, length=135863268]
  153. 開始讀入:Command [skipSize=2717265262, length=135863264]
  154. 結束排序:Command [skipSize=2445538728, length=135863266],用時:2
  155. 開始寫入:Command [skipSize=2445538728, length=135863266]
  156. 結束寫入:Command [skipSize=2445538728, length=135863266],用時:1
  157. 結束整理資料:Command [skipSize=2581401994, length=135863268],用時:3
  158. 開始排序:Command [skipSize=2581401994, length=135863268]
  159. 整理資料:Command [skipSize=2717265262, length=135863264]
  160. 結束記憶體讀入:4s
  161. 開始讀入:Command [skipSize=2853128526, length=135863258]
  162. 結束排序:Command [skipSize=2581401994, length=135863268],用時:2
  163. 開始寫入:Command [skipSize=2581401994, length=135863268]
  164. 結束寫入:Command [skipSize=2581401994, length=135863268],用時:1
  165. 結束整理資料:Command [skipSize=2717265262, length=135863264],用時:3
  166. 開始排序:Command [skipSize=2717265262, length=135863264]
  167. 整理資料:Command [skipSize=2853128526, length=135863258]
  168. 結束記憶體讀入:4s
  169. 開始讀入:Command [skipSize=2988991784, length=135863254]
  170. 結束排序:Command [skipSize=2717265262, length=135863264],用時:2
  171. 開始寫入:Command [skipSize=2717265262, length=135863264]
  172. 結束寫入:Command [skipSize=2717265262, length=135863264],用時:1
  173. 結束整理資料:Command [skipSize=2853128526, length=135863258],用時:3
  174. 開始排序:Command [skipSize=2853128526, length=135863258]
  175. 結束記憶體讀入:4s
  176. 整理資料:Command [skipSize=2988991784, length=135863254]
  177. 開始讀入:Command [skipSize=3124855038, length=135863260]
  178. 結束排序:Command [skipSize=2853128526, length=135863258],用時:2
  179. 開始寫入:Command [skipSize=2853128526, length=135863258]
  180. 結束寫入:Command [skipSize=2853128526, length=135863258],用時:1
  181. 結束整理資料:Command [skipSize=2988991784, length=135863254],用時:3
  182. 開始排序:Command [skipSize=2988991784, length=135863254]
  183. 整理資料:Command [skipSize=3124855038, length=135863260]
  184. 結束記憶體讀入:4s
  185. 開始讀入:Command [skipSize=3260718298, length=135863254]
  186. 結束排序:Command [skipSize=2988991784, length=135863254],用時:2
  187. 開始寫入:Command [skipSize=2988991784, length=135863254]
  188. 結束寫入:Command [skipSize=2988991784, length=135863254],用時:2
  189. 結束整理資料:Command [skipSize=3124855038, length=135863260],用時:4
  190. 開始排序:Command [skipSize=3124855038, length=135863260]
  191. 整理資料:Command [skipSize=3260718298, length=135863254]
  192. 結束記憶體讀入:4s
  193. 開始讀入:Command [skipSize=3396581552, length=135863262]
  194. 結束排序:Command [skipSize=3124855038, length=135863260],用時:1
  195. 開始寫入:Command [skipSize=3124855038, length=135863260]
  196. 結束寫入:Command [skipSize=3124855038, length=135863260],用時:2
  197. 結束整理資料:Command [skipSize=3260718298, length=135863254],用時:3
  198. 開始排序:Command [skipSize=3260718298, length=135863254]
  199. 結束記憶體讀入:4s
  200. 整理資料:Command [skipSize=3396581552, length=135863262]
  201. 開始讀入:Command [skipSize=3532444814, length=135863265]
  202. 結束排序:Command [skipSize=3260718298, length=135863254],用時:1
  203. 開始寫入:Command [skipSize=3260718298, length=135863254]
  204. 結束寫入:Command [skipSize=3260718298, length=135863254],用時:2
  205. 結束整理資料:Command [skipSize=3396581552, length=135863262],用時:3
  206. 開始排序:Command [skipSize=3396581552, length=135863262]
  207. 結束記憶體讀入:4s
  208. 整理資料:Command [skipSize=3532444814, length=135863265]
  209. 開始讀入:Command [skipSize=3668308079, length=135863273]
  210. 結束排序:Command [skipSize=3396581552, length=135863262],用時:2
  211. 開始寫入:Command [skipSize=3396581552, length=135863262]
  212. 結束寫入:Command [skipSize=3396581552, length=135863262],用時:2
  213. 結束整理資料:Command [skipSize=3532444814, length=135863265],用時:3
  214. 開始排序:Command [skipSize=3532444814, length=135863265]
  215. 結束記憶體讀入:4s
  216. 整理資料:Command [skipSize=3668308079, length=135863273]
  217. 開始讀入:Command [skipSize=3804171352, length=135863261]
  218. 結束排序:Command [skipSize=3532444814, length=135863265],用時:2
  219. 開始寫入:Command [skipSize=3532444814, length=135863265]
  220. 結束寫入:Command [skipSize=3532444814, length=135863265],用時:1
  221. 結束整理資料:Command [skipSize=3668308079, length=135863273],用時:3
  222. 開始排序:Command [skipSize=3668308079, length=135863273]
  223. 整理資料:Command [skipSize=3804171352, length=135863261]
  224. 結束記憶體讀入:4s
  225. 開始讀入:Command [skipSize=3940034613, length=135862991]
  226. 結束排序:Command [skipSize=3668308079, length=135863273],用時:2
  227. 開始寫入:Command [skipSize=3668308079, length=135863273]
  228. 結束寫入:Command [skipSize=3668308079, length=135863273],用時:2
  229. 結束整理資料:Command [skipSize=3804171352, length=135863261],用時:3
  230. 開始排序:Command [skipSize=3804171352, length=135863261]
  231. 結束記憶體讀入:4s
  232. 整理資料:Command [skipSize=3940034613, length=135862991]
  233. 結束排序:Command [skipSize=3804171352, length=135863261],用時:1
  234. 開始寫入:Command [skipSize=3804171352, length=135863261]
  235. 結束寫入:Command [skipSize=3804171352, length=135863261],用時:1
  236. 結束整理資料:Command [skipSize=3940034613, length=135862991],用時:3
  237. 開始排序:Command [skipSize=3940034613, length=135862991]
  238. 結束排序:Command [skipSize=3940034613, length=135862991],用時:1
  239. 開始寫入:Command [skipSize=3940034613, length=135862991]
  240. 結束寫入:Command [skipSize=3940034613, length=135862991],用時:1
  241. 合併之前總用時:143
  242. 讀取佇列,寫入目標檔案
  243. 歸併用時:2s
  244. 記憶體對映寫入:1s
  245. 歸併用時:2s
  246. 記憶體對映寫入:1s
  247. 歸併用時:2s
  248. 記憶體對映寫入:1s
  249. 歸併用時:2s
  250. 記憶體對映寫入:1s
  251. 歸併用時:2s
  252. 記憶體對映寫入:1s
  253. 歸併用時:2s
  254. 記憶體對映寫入:1s
  255. 歸併用時:2s
  256. 記憶體對映寫入:1s
  257. 歸併用時:2s
  258. 記憶體對映寫入:2s
  259. 歸併用時:2s
  260. 記憶體對映寫入:1s
  261. 歸併用時:2s
  262. 記憶體對映寫入:1s
  263. 歸併用時:2s
  264. 記憶體對映寫入:1s
  265. 歸併用時:2s
  266. 記憶體對映寫入:1s
  267. 歸併用時:2s
  268. 記憶體對映寫入:1s
  269. 歸併用時:2s
  270. 記憶體對映寫入:1s
  271. 歸併用時:2s
  272. 歸併用時:1s
  273. 記憶體對映寫入:3s
  274. 歸併用時:2s
  275. 歸併用時:2s
  276. 記憶體對映寫入:5s
  277. 記憶體對映寫入:3s
  278. 歸併用時:2s
  279. 記憶體對映寫入:2s
  280. 記憶體對映寫入:2s
  281. 歸併用時:2s
  282. 記憶體對映寫入:2s
  283. 歸併用時:2s
  284. 歸併用時:2s
  285. 記憶體對映寫入:2s
  286. 記憶體對映寫入:1s
  287. 歸併用時:2s
  288. 歸併用時:2s
  289. 記憶體對映寫入:2s
  290. 記憶體對映寫入:2s
  291. 歸併用時:2s
  292. 歸併用時:2s
  293. 記憶體對映寫入:2s
  294. 記憶體對映寫入:2s
  295. 歸併用時:2s
  296. 記憶體對映寫入:2s
  297. 歸併用時:2s
  298. 記憶體對映寫入:2s
  299. 歸併用時:2s
  300. 記憶體對映寫入:2s
  301. 歸併用時:2s
  302. 記憶體對映寫入:2s
  303. 歸併用時:2s
  304. 歸併用時:2s
  305. 記憶體對映寫入:2s
  306. 記憶體對映寫入:2s
  307. 歸併用時:2s
  308. 歸併用時:2s
  309. 記憶體對映寫入:2s
  310. 歸併用時:2s
  311. 記憶體對映寫入:2s
  312. 記憶體對映寫入:2s
  313. 歸併用時:2s
  314. 記憶體對映寫入:2s
  315. 歸併用時:2s
  316. 記憶體對映寫入:2s
  317. 歸併用時:2s
  318. 記憶體對映寫入:2s
  319. 歸併用時:2s
  320. 記憶體對映寫入:2s
  321. 歸併用時:2s
  322. 記憶體對映寫入:2s
  323. 歸併用時:2s
  324. 記憶體對映寫入:2s
  325. 歸併用時:2s
  326. 記憶體對映寫入:2s
  327. 歸併用時:2s
  328. 記憶體對映寫入:2s
  329. 歸併用時:2s
  330. 記憶體對映寫入:2s
  331. 歸併用時:2s
  332. 記憶體對映寫入:2s
  333. 歸併用時:2s
  334. 記憶體對映寫入:2s
  335. 歸併用時:2s
  336. 記憶體對映寫入:2s
  337. 歸併用時:2s
  338. 記憶體對映寫入:2s
  339. 歸併用時:2s
  340. 歸併用時:2s
  341. 記憶體對映寫入:4s
  342. 記憶體對映寫入:2s
  343. 歸併用時:3s
  344. 記憶體對映寫入:2s
  345. 歸併用時:2s
  346. 歸併用時:2s
  347. 記憶體對映寫入:2s
  348. 記憶體對映寫入:2s
  349. 歸併用時:2s
  350. 記憶體對映寫入:2s
  351. 歸併用時:2s
  352. 記憶體對映寫入:2s
  353. 歸併用時:2s
  354. 記憶體對映寫入:2s
  355. 歸併用時:2s
  356. 記憶體對映寫入:2s
  357. 歸併用時:2s
  358. 記憶體對映寫入:2s
  359. 歸併用時:2s
  360. 記憶體對映寫入:2s
  361. 歸併用時:2s
  362. 記憶體對映寫入:2s
  363. 歸併用時:2s
  364. 歸併用時:1s
  365. 歸併用時:2s
  366. 歸併用時:4s
  367. 記憶體對映寫入:6s
  368. 記憶體對映寫入:8s
  369. 記憶體對映寫入:4s
  370. 歸併用時:2s
  371. 歸併用時:2s
  372. 記憶體對映寫入:3s
  373. 記憶體對映寫入:5s
  374. 記憶體對映寫入:2s
  375. 歸併用時:3s
  376. 歸併用時:2s
  377. 記憶體對映寫入:2s
  378. 記憶體對映寫入:2s
  379. 歸併用時:2s
  380. 記憶體對映寫入:1s
  381. 歸併用時:3s
  382. 歸併用時:2s
  383. 記憶體對映寫入:2s
  384. 歸併用時:2s
  385. 記憶體對映寫入:2s
  386. 記憶體對映寫入:2s
  387. 歸併用時:2s
  388. 歸併用時:2s
  389. 記憶體對映寫入:2s
  390. 記憶體對映寫入:2s
  391. 歸併用時:2s
  392. 記憶體對映寫入:1s
  393. 歸併用時:2s
  394. 記憶體對映寫入:2s
  395. 歸併用時:2s
  396. 記憶體對映寫入:2s
  397. 歸併用時:2s
  398. 記憶體對映寫入:2s
  399. 歸併用時:2s
  400. 記憶體對映寫入:1s
  401. 外部排序總用時:351

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29254281/viewspace-1172752/,如需轉載,請註明出處,否則將追究法律責任。

相關文章