Created
March 17, 2016 16:20
-
-
Save brasic/fe4b0b56c50ef368b7bc to your computer and use it in GitHub Desktop.
Quickly copy a postgres table
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| require 'pg' | |
| # Copy a table, e.g. when altering a column to a wider numeric type. | |
| # Minimal usage when db server is localhost: | |
| # SRC_TABLE=table DST_TABLE=table_modified DBNAME=mydb ruby copy_table.rb | |
| class CopyTable | |
| BUFFER_CAPACITY = 2000 | |
| def initialize(src_table:, dst_table:, dbname:, host:, user:, password:) | |
| @src_table = src_table | |
| @dst_table = dst_table | |
| @dbname = dbname | |
| @host = host | |
| @user = user | |
| @password = password | |
| end | |
| def copy! | |
| dst_conn.copy_data("COPY #{@dst_table} FROM STDIN") do | |
| src_conn.copy_data("COPY #{@src_table} TO STDOUT") do | |
| buffered_copy | |
| end | |
| end | |
| end | |
| # Instead of copying each row into the remote database as soon as we have | |
| # it, buffer the copy rows and flush periodically for better performance. | |
| # NB: maintainting an array of strings and joining on flush rather than | |
| # repeatedly concatenating to a string is the approach recommended by | |
| # https://bugs.ruby-lang.org/issues/12024#note-16 since we can't | |
| # preallocate big strings. | |
| def buffered_copy | |
| buffer = [] | |
| count = 0 | |
| while row = src_conn.get_copy_data | |
| buffer << row | |
| if buffer.size >= BUFFER_CAPACITY | |
| count += BUFFER_CAPACITY | |
| print "\r#{count}" | |
| dst_conn.put_copy_data(buffer.join) | |
| buffer = [] | |
| end | |
| end | |
| dst_conn.put_copy_data(buffer.join) if buffer.any? | |
| end | |
| def dst_conn | |
| @dst_conn ||= PG::Connection.open(conn_details) | |
| end | |
| def src_conn | |
| @src_conn ||= PG::Connection.open(conn_details) | |
| end | |
| def conn_details | |
| { | |
| dbname: @dbname, | |
| host: @host, | |
| user: @user, | |
| password: @password | |
| } | |
| end | |
| end | |
| if __FILE__ == $0 | |
| CopyTable.new( | |
| src_table: ENV.fetch('SRC_TABLE'), | |
| dst_table: ENV.fetch('DST_TABLE'), | |
| dbname: ENV.fetch('DBNAME'), | |
| host: ENV['DB_HOST'], | |
| user: ENV['DB_USER'], | |
| password: ENV['DB_PASSWORD'] | |
| ).copy! | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment