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

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

Фон

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

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

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

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

  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? Или любая модификация всего процесса улучшит производительность?


person Lovnlust    schedule 16.10.2014    source источник
comment
A) Похоже, вы начинаете с work.IMP, затем разделяете его на два набора данных, а затем повторно объединяете их в один. Если есть какой-то способ избежать этого, это было бы здорово - не могли бы вы рассказать мне больше о манипуляциях, которые вы делаете на шаге 2 B) Вы работаете в Windows или Linux? Какова аппаратная ситуация с библиотеками (находятся ли они на отдельных дисках, являются ли эти диски своего рода RAID-массивом, какова установка вашей служебной библиотеки (UTILLOC) и т. д.)?   -  person sparc_spread    schedule 16.10.2014
comment
Изучали ли вы варианты массовой загрузки, если вы перемещаете ее между серверами?   -  person Reeza    schedule 16.10.2014
comment
Две системы имеют одинаковую архитектуру? IE обе ​​винды?   -  person DomPazz    schedule 16.10.2014
comment
@sparc_spread на самом деле не разделил его на две части. Я отредактировал свой вопрос, указав более подробную информацию о манипуляциях.   -  person Lovnlust    schedule 17.10.2014
comment
@Reese Я использовал настройку по умолчанию. Как я могу оптимизировать это?   -  person Lovnlust    schedule 17.10.2014
comment
@DomPazz Вы имеете в виду сервер SQL и сервер SAS? Мой компьютер - это Windows ... я мало что знаю об этом.   -  person Lovnlust    schedule 17.10.2014
comment
sourcelib.raw и sourcelib.raw2 начинаются как текстовые файлы или как наборы данных SAS? Пожалуйста, также дайте мне знать о моих вопросах о диске, особенно если targetlib и work находятся на одном или разных дисках.   -  person sparc_spread    schedule 17.10.2014


Ответы (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).

person Joe    schedule 16.10.2014
comment
для 4-го пункта, я сделал это все в РАБОТЕ. Так это уже местное? Что касается 5-го пункта, я должен добавить HAVE2 в WORK к HAVE в сети или добавить HAVE2 в сеть (я поместил его в сеть на предыдущем шаге) к HAVE в сети? Что касается 3-го пункта, я отредактировал свой вопрос, добавив более подробную информацию, не могли бы вы взглянуть, действительно ли это то, что вы рекомендуете? Вариант compress попробую. Спасибо. - person Lovnlust; 17.10.2014
comment
Как мог proc compare выполнять эту работу? Разве он просто не возвращает информацию о несовпадающих записях? - person Lovnlust; 17.10.2014
comment
Точно. Вы используете его для идентификации неидентичных записей, и загружаются только эти записи. Вы можете дать ему указание возвращать только записи из набора данных COMPARE и только те, которые отличаются, которые будут вашим набором для загрузки. - person Joe; 17.10.2014

Вы можете использовать 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, поэкспериментируйте с опцией данных 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 шагов.


person sparc_spread    schedule 16.10.2014
comment
proc append не будет читать записи из data=. В приведенном выше методе Targetlib.HAVE сначала было пустым, а затем добавлены два больших набора данных HAVE1, HAVE2. Значит, нам все еще нужно прочитать все записи из этих больших наборов данных? - person Lovnlust; 17.10.2014
comment
Да, это было просто, чтобы пропустить один из ваших первоначальных шагов. Однако я работаю над чем-то новым, скоро опубликую... см. вопросы в комментариях к исходному сообщению. - person sparc_spread; 17.10.2014
comment
Сообщение об ошибке вводит в заблуждение. Это означает, что набор данных слишком мал для использования SGIO. Для получения дополнительной информации см. (support.sas.com/resources/papers/Flexibility_by_Design.pdf) и (support.sas.com /documentation/cdl/en/hostwin/67279/PDF/default/). - person sparc_spread; 20.10.2014
comment
Сервер вроде как на основе sql. Я пробовал всеми способами оптимизировать код, но производительность по-прежнему очень плохая (но ms-sql может сделать это менее чем за 2 минуты). Я предполагаю, что это что-то связанное с архитектурой сервера. - person Lovnlust; 21.10.2014
comment
Если вы можете сделать это быстрее в MS-SQL, я бы придерживался этого. - person sparc_spread; 21.10.2014