Совет дня №6
Если вы работаете с Postgres, команда COPY должна стать вашим другом. COPY перемещает данные с сервера на клиент и обратно в потоковом режиме. Она подходит для забора больших данных и вставки. COPY эффективнее, чем массовые INSERT и SELECT с пагинацией.
В режиме чтения COPY забирает данные из таблицы или произвольного
запроса. Данные передаются в один из трех пунктов назначения: клиенту, в файл
или процессу. Процессом может быть выражение, например 'gzip -9 > output.gzip'.
В режиме записи COPY ожидает таблицу. Данные принимаются либо от клиента, либо из файла, либо от процесса.
С помощью COPY можно сделать потоковую обработку. В джаве для этого служит класс
CopyManager, который ожидает OutputStream. Этот стрим можно обернуть в
PipedInputStream и читать его в другом потоке. Данные могут быть огромны, но
вы не израсходуете память – все будет проходить в полете порциями.
COPY позволяет забрать таблицу целиком, не выгружая результат в память. Я часто этим пользуюсь: каждое утро запускается задача, которая сбрасывает большие таблицы в файл. Позже я работаю с файлами, не напрягая базу.
Можно вставлять огромные таблицы через COPY параллельно в несколько потоков. Один поток колбасит первую четверть файла, второй – вторую и так далее. Прирост скорости почти линейный.
COPY поддерживает три формата данных: текстовый, CSV и двоичный. Первые два содержат данные в виде текста и отличаются разделителями. Их удобно просматривать, но числа занимают больше места, а многие символы экранируются. Двоичный формат компактный, в нем ничего не экранируется. Его структура довольно простая: фиксированный заголовок, потом набор строк. Каждая строка – набор пар (длина, содержимое). Если значение NULL, то длина равна -1, а содержимого нет.
COPY полезен в тестах: вместо того, чтобы вставлять данные штучно, можно хранить файлы CSV с именами таблиц. Специальная фикстура пробегает папку и копирует CSV в нужные таблицы. Файлы можно редактировать в Экселе.
В консоли psql есть команда \copy. Ее синтаксис в точности повторяет запрос COPY. Разница в том, что \copy связывает удаленный сервер с локальной машиной. Например, если выполнить
copy users (id, email) to '/path/to/file.csv' with (format csv)
, то файл будет создан на сервере Postgres. Если предварить copy обратной
чертой, psql запросит с сервера поток и направит в локальный файл
/path/to/file.csv. По аналогии работает вставка: \copy читает локальный файл
и шлет поток сообщений.
Надеюсь, я смог вас заинтересовать.
Нашли ошибку? Выделите мышкой и нажмите Ctrl/⌘+Enter