Самый быстрый способ скопировать огромный набор данных на сервер в SAS

Отредактировано 21 октября

Фон

Необработанные наборы данных (измененные каждый день), хранящиеся на сервере на базе MS-SQL: Sourcelib.RAW и LOCAL файл Excel (остался unchanged).

Мне нужно обновить набор данных WANTнаходит в Targerlib, В настоящее время у меня SQL-коды выполняют такую ​​задачу за 2-3 минуты. Но я хочу знать, может ли SAS сделать то же самое, в то время как время обработки не сильно увеличится.

  1. work.IMP составляет около 6 миллионов записей и около 50 байт на запись.
  2. Идеальный метод должен быть очень эффективным, потому что со временем размер необработанных наборов данных на сервере будет невероятно огромным.
  3. Целевой файл CANNOT быть установлены в одно время, а затем добавлять новые данные к нему каждый день. Потому что, возможно, (даже очень маловероятно) изменения в предыдущих данных.

Согласно @Joe, я должен разрешить обновление целевого файла, используя proc compare, или же update в data step, Вот связанный вопрос, который я разместил Как использовать процедуру сравнения для обновления набора данных

  1. Еще более 10 ГБ свободного места на сервере, чего вполне достаточно. Доступная память в моем компьютере составляет около 3,5 ГБ (не уверен, что это важно)
  2. Благодаря архитектуре сервера, это очень эффективно сделать в MS-SQL. Но я ДЕЙСТВИТЕЛЬНО хочу знать, может ли SAS справиться с этим (когда сервер не так "compatible")

Процесс

  1. Сначала я импортирую данные из файла Excel, а затем subset&tranpose это быть work.IMP, По некоторым причинам этот файл может быть создан только таким образом, когда-либо. Это CANNOT хранить в сервере.
  2. Затем выполните внешнее соединение для work.IMP и один сырой набор данных Sourcelib.RAW1 получить work.HAVE1, Обратите внимание, что work.IMP отсортировано но Sourcelib.RAW1 не отсортировано Внешнее соединение предназначено только (с некоторыми критериями) для определения каждой записи данных.

i.e. case when a.COL1 is '' then b.COL1 else a.COL1 end as COL1

Вы можете рассмотреть этот процесс, чтобы настроить Sourcelib.RAW1 используя work.IMP,

PS1: @sparc_spread предлагает сделать процедуру импорта напрямую на сервер. Но это не будет иметь никакой пользы, чем сделать это в LOCAL, И hash object здесь тоже не поможет.

  1. Затем я подмножество других сырых наборов данных Sourcelib.RAW2 в work.temp, а потом sort это быть work.HAVE2, (Данные в Sourcelib.RAW2 в основном не в порядке.)
  2. Я соединяю work.HAVE1, work.HAVE2 используя proc append (потому что обе таблицы огромны) work.HAVE

PS2: сортировка в step3 чтобы избежать сортировки в конце step4, На самом деле данные Targerlib.WANT не должно быть в порядке. Но так лучше.

  1. В самом конце я копирую work.HAVE на сервер Targetlib.HAVE,

Я сделал большую часть вещи в WORKЭто заняло у меня всего несколько минут. Но step5 может занять у меня полчаса, чтобы закончить копию.

Согласно @Joe, это может происходить в основном из-за того, что связано с сетевым транзитом. I.E минимизировать сетевой транзит

Вопрос

Любой способ улучшить step5? Или любая модификация всего процесса улучшит производительность?

2 ответа

Решение

Пара мыслей.

Во-первых, предполагая, что это набор данных SAS, а не база данных SQL или что-то еще, options compress=binary; это хорошая идея, если предположить, что это в основном числовой (и options compress=character; если не). Либо в большинстве случаев значительно сократит физический размер набора данных.

Во-вторых, 300 МБ не очень в схеме вещей. Моя сеть напишет это менее чем за минуту. Условия вашей сети могут повлиять на некоторые другие ваши решения; например, если единственная медленная точка - это просто копирование данных через нее, то вам необходимо выяснить, как уменьшить это за счет чего-либо еще, что вы делаете.

Если вы ничего не измените, я бы порекомендовал написать have1 непосредственно в сеть, как have, а затем добавить have2 к этому. IE, какой бы шаг ни создавал have1Имейте это, прямо пишите в сеть. Это включает sort шаги, обратите внимание: так что если вы создаете это, то сортируйте его, создавайте его локально и сортируйте out= сетевая библиотека. Это уменьшает общий объем выполненной записи (поскольку вы не пишете бесполезную копию have1 на ваш локальный диск). Это помогает, если локальная запись является релевантной стоимостью для вашего общего процесса, но не поможет, если это почти полностью перегрузка сети.

Копирование файлов с копией ОС почти всегда превосходит любой другой метод копирования, поэтому, если перегрузка по сети является единственным фактором, который вас волнует, вы можете сделать это локально (в РАБОТЕ или в локальном, но постоянном каталоге, например, C:\temp\ или аналогичный), а затем выполнить последний шаг вашего процесса copy c:\temp\have.sas7bdat \\networklocation\whereitgoes\, Это, как правило, превосходит методы SAS для тех же, поскольку может использовать преимущества эффективных методов.

PROC COPY еще один способ обойти перегрузку сети; это наверное быстрее чем PROC APPEND (если локальная запись незначительна, как это было бы для меня для данных <1 ГБ), и имеет то преимущество, что она немного безопаснее на случай, если что-то случится во время транспортировки. (Добавить также должно быть хорошо, но с COPY вы точно знаете, что ничего не изменилось из вчерашнего файла.)

Наконец, вы можете найти способ разрешить обновление целевого файла. Это не так уж сложно сделать в большинстве случаев. Одним из примеров будет сохранить копию вчерашнего файла, сделать PROC COMPARE в сегодняшний файл, а затем включите в файл обновления каждую запись, которая изменяется (независимо от того, что это изменение). Затем удалите все подходящие старые записи из целевого файла и добавьте новые записи. Это очень быстро сравнительно с точки зрения общего количества записей, отправленных по сети, поэтому экономит много времени в целом, если перегрузка сети является основной проблемой (но для выполнения PROC COMPARE требуется больше процессорного времени).

Ты можешь использовать PROC APPEND чтобы эффективно создать новый набор данных, а не просто добавить к существующему - таким образом, вы можете использовать это, чтобы в основном объединить шаги 3 и 4 в это:

/* To fulfill requirement 4, delete existing Targetlib.HAVE */
PROC DELETE LIBRARY="Targetlib" DATA="HAVE"; 
RUN;

/* Targetlib.HAVE does not yet exist, the first APPEND will create it */
PROC APPEND BASE="Targetlib.HAVE" DATA="work.HAVE1";
RUN;

PROC APPEND BASE="Targetlib.HAVE" DATA="work.HAVE2";
RUN;

Это должно сэкономить, по крайней мере, некоторое время, но это все еще не решит все ваши проблемы... У меня есть несколько дополнительных вопросов, которые я поставил в комментариях к вопросу и буду изменять этот ответ, насколько смогу, основываясь на них.


Обновление 1

Вот способ сделать левое соединение и конкатенацию за один шаг и немедленно записать результаты в targetlib, Я не могу гарантировать, что это будет быстрее, но это стоит попробовать. я использовал key а также val в качестве имен полей замените, как считаете нужным.

PROC SQL _METHOD;
    CREATE TABLE targetlib.HAVE
    AS
    SELECT
        a.key ,
        CASE WHEN MISSING (a.val) THEN b.val ELSE a.val END AS val  
    FROM
        Sourcelib.RAW1 AS a
    LEFT JOIN
        IMP AS b
        ON
            a.key = b.key
    UNION
    SELECT
        c.*
    FROM
        Sourcelib.RAW2 AS c
    ORDER BY
        key
;
QUIT;
RUN;

_METHOD является редко документированной функцией SAS, которая печатает план запроса, см. эту ссылку. Это может дать вам больше понимания. Кроме того, я предполагаю, что IMP был уже импортирован из Excel, и что он находится в WORK, Эксперимент, чтобы увидеть, импортирует ли его targetlib и замена IMP as b с targetlib.IMP as b здесь быстрее.

Поскольку вы работаете в Windows, поэкспериментируйте с опцией data SGIO=YES после имен наборов данных: например Sourcelib.RAW1 AS a становится Sourcelib.RAW1 (SGIO=YES) AS a, Для получения дополнительной информации о Windows SGIO и SAS см. Эту ссылку и эту более старую, но более полную.

Подход, который мог бы быть более эффективным, состоял бы в том, чтобы избежать объединения и использовать вместо этого хеш-объект: хорошую документацию по хеш-объекту можно найти здесь, а хороший лист подсказок - здесь. Не ясно, будет ли это быстрее - imp имеет 6 миллионов записей, но при 50 байтах на запись, это около 300 МБ, что вписывается в вашу оперативную память. Производительность хеш-таблицы с таким количеством записей во многом будет зависеть от алгоритма хеширования SAS. В любом случае, вот код, использующий хеш-объект. В нем мы предполагаем, что в IMP набор данных, val поле было переименовано в val2,

DATA targetlib.HAVE (DROP = rc val2);
    LENGTH val2 8. ;

    IF (_N_ = 1) THEN DO;
        DECLARE HASH h (DATASET: "IMP") ;
        h.DEFINEKEY ('key');
        h.DEFINEDATA ('val2');
        h.DEFINEDONE ();
    END;

    SET 
        sourcelib.RAW1
        sourcelib.RAW2
    ;

    IF MISSING (val) THEN DO;
        rc = h.find();
        IF (rc = 0) THEN DO;
            val = val2;
        END;
    END;
RUN;
PROC SORT DATA = targetlib.HAVE ; BY KEY ; RUN ;

Попробуйте и посмотрите, будет ли это быстрее. Еще раз, экспериментируйте с местоположением IMP, с помощью SGIOи т. д. PROC SORT в конце может быть дорого; если единственной причиной, по которой вы раньше сортировали, было присоединение, пропустите это.

В целом, ваш подход к SAS должен заключаться в том, чтобы сделать как можно меньше операций ввода-вывода и найти способы объединения нескольких действий в одну запись из PROC или же DATA шаг.


Другие вопросы по тегам