2013-08-05 2 views
0

У меня есть программа SAS, которая динамически строит таблицу с помощью макроса, как так:Оптимизировать строит таблицу SAS с макросами

%macro Projection; 
%do i=1 %to &number_of_Years; 
    %Advance_Years; 
    proc sql; 
     create table Projection as 
     select *, Year_&previous_year.*(1+return) as Year_&current_year. 
     from Projection; 
     quit; 
%end; 
%Mend Projection; 

%Projection; 

Это упрощенная версия моего кода. Макрос %Advance_Years в основном продвигает &current_year и &previous_year макрос 1 года. Как вы можете видеть, эта таблица получает 1 переменную в год. Проблема в том, что количество строк для этой таблицы может достигать сотен тысяч, и я видел, как время выполнения увеличилось, достигнув нескольких часов.

Я пробовал option compress=yes, и это помогло сократить время выполнения, но не много. Я пробовал большинство советов и советов SAS для ускорения выполнения, но опять же, не так уж и много. Я запускаю Base SAS 9.2 на 32b.

Я думаю, что я ошибаюсь в технике добавления переменных. Является ли тот факт, что я перезаписываю таблицу в каждом цикле, влияет на эффективность выполнения? Если да, то как я могу переписать это как эффективный код MOST? Пожалуйста, имейте в виду, что я не могу «переставить» таблицу и просто добавить несколько строк. Заранее спасибо!

+0

Почему вы не можете добавить строки в существующую таблицу? –

+0

Это произвольное ограничение. Оригинальная программа построена вокруг концепции, что столбцы представляют собой временную прогрессию. Транспонирование таблицы в основном означало бы, что я должен переписать всю программу. – Pane

+1

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

ответ

3

Там нет причин, чтобы сделать это в более чем один проход через данные, если я не» m отсутствует что-то важное здесь. Это, безусловно, проблема, как вы догадываетесь.

data projection; 
set <whatever came before projection>; 
array years year_1-year_&number_of_years.; 
year_1=1; 
do _t = 2 to dim(years); 
years[_t] = years[_t-1]*(1+return); 
end; 
run; 

SQL, решение не было бы ужасно отличается, за исключением того, что без массивов вам придется строить его динамически через макроязыком - но все-таки в один ... from projection; проход.

%macro add_to_sql(current_year=,previous_year=); 
Year_&previous_year.*(1+return) as Year_&current_year. 
%mend add_to_sql; 

data calllist; 
do current_year = 2 to &number_of_years; 
previous_year=current_year-1; 
output; 
end; 
run; 

proc sql; 
select cats('%add_to_sql(current_year=',current_year,',previous_year=',previous_year,')') 
into :addlist separated by ',' from callist; 
select year_1,&addlist from projection; 
quit; 

Несколько примечаний: вы должны попытаться управлять выполнением программы посредством данных, когда это возможно. Хотя это выглядит немного менее эффективным, его гораздо легче читать и отлаживать, чем иметь макрос, чтобы увеличить некоторые макропеременные, что дополнительно нарушает версию SAS защищенного/частного/любого объекта, ориентированного на то, что нет, - что SAS не возражает, но на самом деле плохой стиль. Вызовите макросы с параметрами и предоставите их из вызывающей среды; макрос не должен изменять макропеременные в вызывающей среде. Следовательно, у меня есть add_to_sql, настроенный с параметрами, и набор данных, который содержит эти параметры (может быть набором данных, который импортируется из другого места или создается как здесь). & number_of_years также должен быть параметром записи для этого модуля, если это не основная программа, и в этом случае глобальная переменная в порядке.

В общем, в SAS (и на других языках, но особенно в SAS) время ввода/вывода будет превзойти любое другое время обработки, в частности, учитывая текущую экономичность вычислений (процессоры супермощные, много заказов по величине быстрее, чем 10 лет назад, а если вы находитесь на флэш-памяти, скорость вашего хранения меньше, чем на порядок быстрее, чем 10 лет назад).

+0

Я собираюсь попробовать ваш метод Data step, а также [this] (http: //heuristically.wordpress.com/2010/08/06/make-proc-sql-update-faster-sas-call-execute-data-step/) для обновления в proc sql. – Pane

+0

Это решение функционально эквивалентно Gordon's ниже, я не думаю, что это необходимо в этом случае, потому что вы действительно не делаете кучу обновлений. – Joe

1

Я полагаю, что запись за один стол вызывает множество проблем с производительностью.

Позвольте мне описать решение, которое, как я думаю, вы должны предпринять. Мои навыки программирования макросов SQS немного ржавые, поэтому я оставлю фактическую реализацию вам.

Во-первых, изменить таблицу Projection, чтобы иметь столбцы, которые вы хотите добавить. В идеале вы бы сделали это в одном заявлении. Но вы можете сделать что-то вроде:

%do i=1 %to &number_of_Years; 
    %Advance_Years; 
    alter table Projection 
     add Year_&current_year double; 
%end; 

Затем перебрать и сделать расчеты на месте:

%do i=1 %to &number_of_Years; 
    %Advance_Years; 
    update table Projection 
     set Year_&current_year = Year_&previous_year.*(1+return); 
%end; 
+0

Это выглядит довольно многообещающе, спасибо. Я буду проверять это завтра и дать некоторые отзывы. – Pane

+0

Обратная связь: Я внедрил метод alter/update, но это не сильно изменило :(, время выполнения все равно примерно такое же. – Pane

Смежные вопросы