<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Join and aggregation of large tables - is there a faster way? in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919405#M362141</link>
    <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/12447"&gt;@Patrick&lt;/a&gt;&amp;nbsp;, so for hash table approach adding some "brute computing force" gives a nice boost.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;There is one more interesting observation (regardless the fact the array approach has some data reading issues, which is totally bizarre to me).&lt;/P&gt;
&lt;P&gt;When you take a look at my or&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/370514"&gt;@Bernd_S&lt;/a&gt;&amp;nbsp; log from SAS 9.4, you will notice there is almost no difference between CPU time and Real time, e.g.&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/370514"&gt;@Bernd_S&lt;/a&gt;&amp;nbsp; log says:&lt;/P&gt;
&lt;P&gt;for array:&lt;/P&gt;
&lt;P&gt;real time 1:04.32&lt;BR /&gt;user cpu time 55.27 seconds&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;for hash:&lt;/P&gt;
&lt;P&gt;real time 4:46.23&lt;BR /&gt;user cpu time 4:41.24&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;
&lt;P&gt;In case of Viya there is almost none CPU time reported, I wonder what is the reason?&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Another experiment I did was running both codes (hash and array) on my "home made Viya" which is "SAS9 + work in RAM disk", result was that there was no difference in processing time between data in RAM drive and data in SSD drive...&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Bart&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;P.S.&amp;nbsp;RamDrive tool i'm using is&amp;nbsp;imdisk-toolkit (&lt;A href="https://sourceforge.net/projects/imdisk-toolkit/" target="_blank"&gt;https://sourceforge.net/projects/imdisk-toolkit/&lt;/A&gt;)&lt;/P&gt;</description>
    <pubDate>Fri, 08 Mar 2024 08:36:01 GMT</pubDate>
    <dc:creator>yabwon</dc:creator>
    <dc:date>2024-03-08T08:36:01Z</dc:date>
    <item>
      <title>Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919181#M362060</link>
      <description>&lt;P&gt;Hello,&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I have a rather large join and aggregation, which is part of a higher level program. The join and aggregation is used many times in the higher level program with tables which are structurally the same but contain different data. Therefore it would be nice to speed this step up.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;&lt;CODE class=""&gt; /* 
    We have one large table A (~ 550 Mio. lines) and one smaller table B (~ 1.2 Mio. lines).
    Table A is sorted by i id id_2, table B is sorted by id id_2. B only contains id and id_2 entries of A, due to the creation of the tables.
    Table A might contain not every entry of id and id_2 of table B. This should probably be irrelevant for the question and is therefore not modeled here  
 */  


/***************************************************************************************************/
/* Create sample data: */
 %let max_i = 5600;
 %let max_id = 55000;
 %let max_category = 22;

 data _ids;
 	do ID = 1 to &amp;amp;max_id.;
		ID_2 = "1";
		output;
		/* We have some ids for which id_2 is 1 and 0*/
		if rand('uniform',0,1) &amp;lt; 0.01 then do; ID_2="0"; output; end;
	end;
 run;
 proc sort data=_ids; by ID ID_2;run;

 data _i;
	do I = 1 to &amp;amp;max_i.;
		output;
/*		Not every i is given. */
/*		Furthermore it is not modeled here but might be important: we don't know max_i and max_i is different for different table As.*/
		if rand('uniform',0,1) &amp;lt; 0.01 then i+1;
	end;
 run;

/* Cartesian Product for table A*/
 proc sql;
 	create table table_A as
	select A.I
		  ,B.ID
		  ,B.ID_2
		  ,ceil(rand('uniform',0,&amp;amp;max_category.)) as CATEGORY
	from _i A
	left join _ids B
	on 1 = 1
	order by A.I, B.ID, B.ID_2;
 quit;

/* Create table B*/
 data table_B;
 	set _ids;
	do CATEGORY = 1 to &amp;amp;max_category.;
		x = rand('uniform',0,1);
		output;
	end;
 run;



/***************************************************************************************************/
/* Join and Aggregation */

 /* Option A: Join and group by */
proc sql;
create table WANT_OPTION_A as
select  A.I 
		,sum (B.X) as SUM_X 
from table_A(sortedby=I ID ID_2) A
inner join table_B(sortedby=ID ID_2 CATEGORY) B
on 	A.ID = B.ID and 
	A.ID_2 = B.ID_2 and
	A.CATEGORY = B.CATEGORY
group by A.I;
quit;



 /* Option B: Hash*/
data WANT_OPTION_B(keep = I SUM_X);

      if 0 then set table_B;
      if _N_ = 1 then do;
         declare hash HH_BEW (dataset: 'table_B');
         HH_BEW.defineKey  ('ID', 'ID_2', 'CATEGORY');
         HH_BEW.defineData ('X');
         HH_BEW.defineDone ();

      end;

      set table_A(sortedby=I ID ID_2);
      by I;
	  call missing (X);
      retain SUM_X;
      if first.I then SUM_X = 0;

      RC = HH_BEW.find ();

      SUM_X = sum (SUM_X, X);
      
      if last.I;
 run;

&lt;/CODE&gt;&lt;/PRE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Unfortunately I cannot change underlying settings like memsize.&lt;/P&gt;&lt;P&gt;However I have some control over the size of table A in the higher level program without loosing significant time there, i.e. I can split table A into several tables (e.g. two with 330 Mio. lines) or aggregate the table (e.g. two with 660 Mio. lines into one with 1260 Mio. lines).&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;STRONG&gt;Testresults:&lt;/STRONG&gt;&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;For a table A with 330 Mio. lines:&lt;UL&gt;&lt;LI&gt;Option A: ~ 4 minutes user time and ~ 7 minutes cpu time&lt;/LI&gt;&lt;LI&gt;Option B: ~ 4 minutes user time and ~ 4 minutes cpu time&lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;&lt;LI&gt;For a table A with 660 Mio. lines:&lt;/LI&gt;&lt;UL&gt;&lt;LI&gt;Option A: ~ 8 minutes user time and ~ 14 minutes cpu time&lt;/LI&gt;&lt;LI&gt;Option B: ~ 8 minutes user time and ~ 8 minutes cpu time&lt;/LI&gt;&lt;/UL&gt;&lt;/UL&gt;&lt;P&gt;There seems to be no need to change the size of table A.&amp;nbsp; Option B is better but only regarding cpu time.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;I thought about combining ID, ID_2 and CATEGORY into a single key and using a format on table A. This would get rid of the join or hash. However I still need the full table A with the CATEGORY information for another join, so there is no way I can save time with creating only the aggregate and not table A. I have never used a format for this before, hence it would be a small challenge.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Would this be still worth a try? Or is there any other way to speed something up?&amp;nbsp;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Thank you in advance.&lt;/P&gt;</description>
      <pubDate>Wed, 06 Mar 2024 19:07:43 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919181#M362060</guid>
      <dc:creator>Bernd_S</dc:creator>
      <dc:date>2024-03-06T19:07:43Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919201#M362062</link>
      <description>&lt;P&gt;Do you have indexes on the tables? Is it worthwhile to create an index with one of the ID variables?&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A href="https://support.sas.com/resources/papers/proceedings/proceedings/sugi30/008-30.pdf" target="_blank"&gt;https://support.sas.com/resources/papers/proceedings/proceedings/sugi30/008-30.pdf&lt;/A&gt;&lt;/P&gt;</description>
      <pubDate>Wed, 06 Mar 2024 20:27:09 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919201#M362062</guid>
      <dc:creator>Reeza</dc:creator>
      <dc:date>2024-03-06T20:27:09Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919206#M362064</link>
      <description>&lt;P&gt;Can you explain what type of combination of the two datasets you are trying to do?&lt;/P&gt;
&lt;P&gt;Do the key variables uniquely identify the observations in both datasets?&amp;nbsp; if not why not, what does the duplication mean?&lt;/P&gt;
&lt;P&gt;You mentioned aggregation.&amp;nbsp; What type of aggregation are you doing?&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The fastest way to combine two datasets that are already sorted is with the MERGE statement.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data want;
  merge a(in=in1) b(in=in2);
  by id1 id2;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Wed, 06 Mar 2024 21:03:53 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919206#M362064</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2024-03-06T21:03:53Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919213#M362068</link>
      <description>&lt;P&gt;A complete description of the aggregations might be in order.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Proc summary will "aggregate" multiple variables by multiple class/by variables pretty efficiently.&amp;nbsp; So perhaps combine all (or most) of your aggregations into one or a very small number of sets and then use those instead of aggregating with multiple calls using the same data set.&lt;/P&gt;</description>
      <pubDate>Wed, 06 Mar 2024 23:19:30 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919213#M362068</guid>
      <dc:creator>ballardw</dc:creator>
      <dc:date>2024-03-06T23:19:30Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919216#M362070</link>
      <description>&lt;P&gt;Hi&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/370514"&gt;@Bernd_S&lt;/a&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;How about creating Data Step View of the merge, followed by Proc Summary?&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;PROC SORT DATA=work.table_a; BY id id_2 category; Run;

DATA WANT_OPTION_A_v (KEEP=i x)/VIEW=WANT_OPTION_A_v;
	MERGE table_a table_b;
	By id id_2 category;
RUN;
PROC SUMMARY DATA=work.WANT_OPTION_A_v NWAY;
	CLASS i;
	VAR x;
	output out=WANT_OPTION_A_sum(DROP=_:) sum=sum_x;
RUN;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;if i has too large cardinality, you may want to sort the view by i, then use By statement in the Proc Summary&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;PROC SORT DATA=work.table_a; BY id id_2 category; Run;

DATA WANT_OPTION_A_v (KEEP=i x)/VIEW=WANT_OPTION_A_v;
	MERGE table_a table_b;
	By id id_2 category;
RUN;
PROC SORT DATA=WANT_OPTION_A_v OUT=WANT_OPTION_A_srt;
   BY i;
RUN;
PROC SUMMARY DATA=work.WANT_OPTION_A_srt NWAY;
	BY i;
	VAR x;
	output out=WANT_OPTION_A_sum(DROP=_:) sum=sum_x;
RUN;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Hope this helps,&lt;/P&gt;
&lt;P&gt;Ahmed&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 07 Mar 2024 00:46:52 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919216#M362070</guid>
      <dc:creator>AhmedAl_Attar</dc:creator>
      <dc:date>2024-03-07T00:46:52Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919222#M362073</link>
      <description>&lt;P&gt;Thanks for providing sample data and code.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Based on the testing on my laptop the hash lookup is faster than the SQL because it avoids the sorting (which is the multithreaded portion of the SQL).&lt;/P&gt;
&lt;P&gt;&lt;A href="https://support.sas.com/rnd/scalability/tools/fullstim/index.html" target="_self"&gt;Option fullstimer&lt;/A&gt; indicates that on my environment reading the data from disk is not the bottleneck. You should check this on your environment as well.&lt;/P&gt;
&lt;P&gt;Afaik with these results the only thing that really could speed-up processing is faster CPU with a matching throughput reading from disk.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;One other option would be to run this in multiple sessions (multiple CPU's) and process the data in multiple junks but ...the time it would take to determine where to split the data and to invocate these sessions (rsubmit blocks) would likely consume too much extra time to make this worthwhile given the current elapsed time of your single threaded process. And with multiple processes reading the same file in parallel there is then also a chance that I/O becomes the bottleneck.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Just reading table A and loading table B into a hash takes already considerable time.&lt;/P&gt;
&lt;LI-SPOILER&gt;
&lt;PRE&gt;28         options fullstimer msglevel=i;
29         data _null_;
30           set table_a(keep=i id id_2 category);
31         run;

NOTE: There were 308646702 observations read from the data set WORK.TABLE_A.
NOTE: DATA statement used (Total process time):
      real time           1:01.85
      user cpu time       32.73 seconds
      system cpu time     10.75 seconds
      memory              1276.00k
      OS Memory           22120.00k
      Timestamp           03/07/2024 12:54:31 PM
      Step Count                        53  Switch Count  100
      

32         data _null_;
33             if 0 then set table_a(keep=i id id_2 category) table_b(keep=x);
34             declare hash hh_bew (dataset: 'table_b');
35             hh_bew.definekey  ('id', 'id_2', 'category');
36             hh_bew.definedata ('x');
37             hh_bew.definedone ();
38         run;

NOTE: There were 1223244 observations read from the data set WORK.TABLE_B.
NOTE: DATA STEP stopped due to looping.
NOTE: DATA statement used (Total process time):
      real time           0.52 seconds
      user cpu time       0.46 seconds
      system cpu time     0.00 seconds
      memory              134070.12k
      OS Memory           154756.00k
      Timestamp           03/07/2024 12:54:32 PM
      Step Count                        54  Switch Count  4&lt;/PRE&gt;
&lt;/LI-SPOILER&gt;
&lt;P&gt;And here the log from the run on my environment. Please note the the data step hash lookup is similar to a left join (and not an inner join). If you would only want rows in the result set where at least one source row per ID had a match with the hash then some additional logic would be required.&lt;/P&gt;
&lt;LI-SPOILER&gt;
&lt;PRE&gt;28         options fullstimer msglevel=i compress=no;
29         /***************************************************************************************************/
30         /* Join and Aggregation */
31         /* Option A: Join and group by */
32         proc sql _method ;
33           create table WANT_OPTION_A1 as
34             select  A.I
35               ,sum (B.X) as SUM_X
36             from table_A(sortedby=I ID ID_2 keep=i id id_2 category) A
37               inner join table_B(sortedby=ID ID_2 CATEGORY) B
38                 on  A.ID = B.ID and
39                 A.ID_2 = B.ID_2 and
40                 A.CATEGORY = B.CATEGORY
41               group by A.I;

NOTE: SQL execution methods chosen are:

      sqxcrta
          sqxsumg
              sqxsort
                  sqxjhsh
                      sqxsrc( WORK.TABLE_A(alias = A) )
                      sqxsrc( WORK.TABLE_B(alias = B) )
NOTE: SAS threaded sort was used.
NOTE: Table WORK.WANT_OPTION_A1 created, with 5551 rows and 2 columns.

42         quit;
NOTE: PROCEDURE SQL used (Total process time):
      real time           5:43.96
      user cpu time       5:27.71
      system cpu time     22.79 seconds
      memory              1147505.04k
      OS Memory           1166680.00k
      Timestamp           03/07/2024 12:11:41 PM
      Step Count                        39  Switch Count  478
      

43         
44         /* Option B: Hash*/
45         data want_option_b(keep = i sum_x);
46           if _n_ = 1 then
47             do;
48               if 0 then set table_a(keep=i id id_2 category) table_b(keep=x);
49               declare hash hh_bew (dataset: 'table_b');
50               hh_bew.definekey  ('id', 'id_2', 'category');
51               hh_bew.definedata ('x');
52               hh_bew.definedone ();
53             end;
54         
55           set table_a(keep=i id id_2 category);
56           by i;
57           if hh_bew.find()=0 then sum_x + x;
58           if last.i then
59             do;
60               output;
61               call missing(sum_x);
62             end;
63         run;

NOTE: There were 1223244 observations read from the data set WORK.TABLE_B.
NOTE: There were 308646702 observations read from the data set WORK.TABLE_A.
NOTE: The data set WORK.WANT_OPTION_B has 5551 observations and 2 variables.
NOTE: DATA statement used (Total process time):
      real time           4:27.76
      user cpu time       3:09.60
      system cpu time     20.25 seconds
      memory              134490.06k
      OS Memory           154508.00k
      Timestamp           03/07/2024 12:16:09 PM
      Step Count                        40  Switch Count  433
      &lt;/PRE&gt;
&lt;/LI-SPOILER&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 07 Mar 2024 02:13:19 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919222#M362073</guid>
      <dc:creator>Patrick</dc:creator>
      <dc:date>2024-03-07T02:13:19Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919257#M362091</link>
      <description>&lt;P&gt;Hi,&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;thanks everybody for the replies.&lt;/P&gt;&lt;P&gt;Since questions were asked about the tables and what I try to achieve, I will provide more background information.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Table A has the primary key i, id, id_2 and its creation is such that it is sorted by i. I think a can change the higher level program such that table A would be sorted by i, id, id_2 without much overhead if this helps.&lt;/P&gt;&lt;P&gt;Table B has the primary key id, id_2, category. It is sorted by the primary key.&lt;/P&gt;&lt;P&gt;The aggregation I'm talking about is the sum(x) over each i.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;The higher level program is basically a monte carlo simulation, which is already run on multiple sessions. I need to simulate a large number of scenarios, i.e.&amp;nbsp; max_i is the number of scenarios of one session or one run of a session and the total number of all scenarios is the sum of max_i over all runs of the sessions. Table A is one outcome of one run of a session, i.e. for nearly each id, id_2 of table B a category is simulated for each scenario i. The simulation of the category is rather complex and I need the whole information in table A also for other purposes. Each run creates a different table A. Furthermore I must calculate the sum of x for each scenario i. Table B is basically a mapping of each CATEGORY of each id, id_2 to a value x.&amp;nbsp; The values of table B are the same for each run. Therefore this rather large join/aggregation must be carried out several times. It is the most time consuming part of the whole program and I would be able to decrease the total time of the higher level program by a significant amount if this step could be run e.g. a minute faster.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/12447"&gt;@Patrick&lt;/a&gt;: Thanks for your analysis, this coincides with my findings. Your programmed hash is slightly faster than mine. So right now this is my prefered solution. Due to the nature of the tables the left join always hits, therefore we can skip the if hh_bew.find()=0 part.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/13879"&gt;@Reeza&lt;/a&gt;: Since I'm creating the tables in the higher level program I could put indexes on the tables. I'm however not familiar with indexes.&amp;nbsp; Depending on&amp;nbsp;max_i I retrieve a different percent of the rows of table B. For&amp;nbsp;max_i=5600 around 80 % are retrieved. Could this help? How would this step look with indexes?&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/13868"&gt;@AhmedAl_Attar&lt;/a&gt;: Thanks for your suggestion. I used your code and on my machine it seems like the real time of it is slightly longer than&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/12447"&gt;@Patrick&lt;/a&gt;s suggestion and the cpu time is around the double of the hash method.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 07 Mar 2024 08:48:39 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919257#M362091</guid>
      <dc:creator>Bernd_S</dc:creator>
      <dc:date>2024-03-07T08:48:39Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919267#M362097</link>
      <description>&lt;P&gt;I used your test data for tests&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Table A is ~9.2GB and B is ~38MB.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;I observed the ID_2 is character and&amp;nbsp;&lt;SPAN&gt;ID_2 values are "1" or "0".&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;If you can make &lt;STRONG&gt;ID_2 to be numeric&lt;/STRONG&gt; with 1 and 0 instead "1" and "0":&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt; data _ids;
 	do ID = 1 to &amp;amp;max_id.;
		ID_2 = 1; /* &amp;lt;-- numeric */
		output;
		/* We have some ids for which id_2 is 1 and 0*/
		if rand('uniform',0,1) &amp;lt; 0.01 then do; ID_2=0; output; end;
	end;
 run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Then you could use a&lt;STRONG&gt; temporary array&lt;/STRONG&gt; for look-up.&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%let max_i = 5600;
%let max_id = 55000;
%let max_category = 22;
%let max_ID_2=1;
                                        /* if ID_2 is numeric */
%let range_up = %sysevalf(&amp;amp;max_id.*1000 + &amp;amp;max_ID_2.*100 + &amp;amp;max_category.);
%put &amp;amp;=range_up.;


/* Option C: Array*/
data WANT_OPTION_B_array(keep = I SUM_X);

  /* populate array */
  array XX[&amp;amp;range_up.] _temporary_; /* instead hash table */
  do until(eofB);
    set table_B end=EOFB;
    XX[ID*1000 + ID_2*100 + CATEGORY]=X;
  end;

  do until (EOFA);
    set table_A end=EOFA;
    by I;

    if first.I then SUM_X = 0;
    SUM_X + XX[ID*1000 + ID_2*100 + CATEGORY]; /* direct keys addressing */
    
    if last.I then output;
  end;
  stop;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;With numeric ID_2 the result for the &lt;STRONG&gt;hash table&lt;/STRONG&gt; code on my machine was:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;NOTE: There were 1221506 observations read from the data set WORK.TABLE_B.
NOTE: There were 307875035 observations read from the data set WORK.TABLE_A.
NOTE: The data set WORK.WANT_OPTION_B has 5545 observations and 2 variables.
NOTE: DATA statement used (Total process time):
      real time           1:22.39
      cpu time            1:22.73
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;and the result with &lt;STRONG&gt;Array&lt;/STRONG&gt; was:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;NOTE: There were 1221506 observations read from the data set WORK.TABLE_B.
NOTE: There were 307875035 observations read from the data set WORK.TABLE_A.
NOTE: The data set WORK.WANT_OPTION_B_ARRAY has 5545 observations and 2 variables.
NOTE: DATA statement used (Total process time):
      real time           13.81 seconds
      user cpu time       12.36 seconds
      system cpu time     1.65 seconds
      memory              430637.46k
      OS Memory           458620.00k
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;(printout is with Fullstimer, so you can see memory usage too)&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The formula for array size:&lt;/P&gt;
&lt;P&gt;&lt;CODE class=" language-sas"&gt;%let range_up = %sysevalf(&amp;amp;max_id.*1000 + &amp;amp;max_ID_2.*100 + &amp;amp;max_category.);&lt;/CODE&gt;&lt;/P&gt;
&lt;P&gt;is based on assumption that category has 2 digits, and ID_2 is 0 or 1.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;If number of categories changes to more than 99 or ID_2 increases above 9 you will have to adjust the 1000 and 100 accordingly.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Hope it helps.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Bart&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;P.S. I learned this technique from&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/21262"&gt;@hashman&lt;/a&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;[EDIT:]&lt;/P&gt;
&lt;P&gt;P.S.2&lt;/P&gt;
&lt;P&gt;Linear pass through data was very fast, but only ~6 seconds faster than "array lookup":&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;220    data WANT_OPTION_B_read(keep = I SUM_X);
221
222
223        set test.table_A(sortedby=I ID ID_2);
224        by I;
225
226
227         SUM_X +1;
228        if last.I;
229   run;

NOTE: There were 308619066 observations read from the data set WORK.TABLE_A.
NOTE: The data set WORK.WANT_OPTION_B_READ has 5558 observations and 2 variables.
NOTE: DATA statement used (Total process time):
      real time           7.52 seconds
      cpu time            7.56 seconds
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;{EDIT 2:}&amp;nbsp;&lt;/P&gt;
&lt;P&gt;P.S.3 I did additional run of the hash approach to see memory usage:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;NOTE: There were 1221506 observations read from the data set WORK.TABLE_B.
NOTE: There were 307875035 observations read from the data set WORK.TABLE_A.
NOTE: The data set WORK.WANT_OPTION_B has 5545 observations and 2 variables.
NOTE: DATA statement used (Total process time):
      real time           1:22.18
      user cpu time       1:20.67
      system cpu time     1.60 seconds
      memory              91185.12k
      OS Memory           119216.00k
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Array took ~4.5 times more RAM.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;But! if ID_is only 1 or 0 then we can re-arrange lookup key calculation to:&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%let range_up = %sysevalf(&amp;amp;max_id. + &amp;amp;max_ID_2.*1e7 + &amp;amp;max_category.*1e5);
%put &amp;amp;=range_up.;



/* Option C: Array*/
data WANT_OPTION_B_array(keep = I SUM_X);

  /* populate array */
  array XX[&amp;amp;range_up.] _temporary_;
  do until(eofB);
    set table_B end=EOFB;
    XX[ID + ID_2*1e7 + CATEGORY*1e5]=X;
  end;

  do until (EOFA);
    set table_A end=EOFA;
    by I;

    if first.I then SUM_X = 0;
    SUM_X + XX[ID + ID_2*1e7 + CATEGORY*1e5];
    
    if last.I then output;
  end;
  stop;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;this makes array maximal size 12255000 instead 55000122 which is ~4 times smaller and the result is even better (with array RAM size comparable to hash table RAM):&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;NOTE: There were 1221506 observations read from the data set WORK.TABLE_B.
NOTE: There were 307875035 observations read from the data set WORK.TABLE_A.
NOTE: The data set WORK.WANT_OPTION_B_ARRAY has 5545 observations and 2 variables.
NOTE: DATA statement used (Total process time):
      real time           9.78 seconds
      user cpu time       8.35 seconds
      system cpu time     1.53 seconds
      memory              96686.93k
      OS Memory           124672.00k
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 07 Mar 2024 10:27:14 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919267#M362097</guid>
      <dc:creator>yabwon</dc:creator>
      <dc:date>2024-03-07T10:27:14Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919287#M362101</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/35763"&gt;@yabwon&lt;/a&gt;&amp;nbsp;Impressive! I knew that using a temporary array is faster than a hash lookup but I didn't expect such a significant difference.&lt;/P&gt;
&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/370514"&gt;@Bernd_S&lt;/a&gt;&amp;nbsp;If your actual data allows for it then using a temporary array appears to make a very significant impact. And of course what also should drastically reduce overall elapsed time is running your multiple simulation and aggregation steps in multiple processes in parallel - either just via running multiple batch jobs in parallel or then if using EG/Studio a single program spawning multiple sessions (rsubmit).&lt;/P&gt;</description>
      <pubDate>Thu, 07 Mar 2024 11:57:21 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919287#M362101</guid>
      <dc:creator>Patrick</dc:creator>
      <dc:date>2024-03-07T11:57:21Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919289#M362103</link>
      <description>&lt;P&gt;It's a very good article!&lt;/P&gt;</description>
      <pubDate>Thu, 07 Mar 2024 12:00:57 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919289#M362103</guid>
      <dc:creator>yabwon</dc:creator>
      <dc:date>2024-03-07T12:00:57Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919290#M362104</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/12447"&gt;@Patrick&lt;/a&gt;&amp;nbsp;I saw in your post you did nice "processing time analysis" too, could you be so kind and check that "array approach" time on your machine? So we could have broader view.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Bart&lt;/P&gt;</description>
      <pubDate>Thu, 07 Mar 2024 12:04:47 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919290#M362104</guid>
      <dc:creator>yabwon</dc:creator>
      <dc:date>2024-03-07T12:04:47Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919292#M362105</link>
      <description>&lt;P&gt;Hi,&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/35763"&gt;@yabwon&lt;/a&gt;&amp;nbsp;Thank you very much, that is exactly what I need. I also didn't know and didn't expect that the use of an array would be so much faster. I can make ID_2 numeric.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Your solution on my machine:&amp;nbsp;&amp;nbsp;&lt;/P&gt;&lt;P&gt;real time 1:04.32&lt;BR /&gt;user cpu time 55.27 seconds&lt;BR /&gt;system cpu time 9.06 seconds&lt;BR /&gt;memory 96561.62k&lt;BR /&gt;OS Memory 132524.00k&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/12447"&gt;@Patrick&lt;/a&gt;s Hash solution:&lt;/P&gt;&lt;P&gt;real time 4:46.23&lt;BR /&gt;user cpu time 4:41.24&lt;BR /&gt;system cpu time 5.00 seconds&lt;BR /&gt;memory 132394.82k&lt;BR /&gt;OS Memory 168216.00k&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/12447"&gt;@Patrick&lt;/a&gt;&amp;nbsp;Thanks again for your suggestions and analysis.&lt;/P&gt;</description>
      <pubDate>Thu, 07 Mar 2024 12:35:05 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919292#M362105</guid>
      <dc:creator>Bernd_S</dc:creator>
      <dc:date>2024-03-07T12:35:05Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919294#M362107</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/35763"&gt;@yabwon&lt;/a&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Here you go. I've "tweaked" your code slightly so it accepts id_2 as character variable. I've also made the array two dimensional to not need to multiply ID by 1000.&lt;/P&gt;
&lt;LI-SPOILER&gt;
&lt;PRE&gt;29         options fullstimer msglevel=i ps=max;
30         /************ hash lookup ************/
32         data want_HASH(keep = i sum_x);
33           if _n_ = 1 then
34             do;
35               if 0 then set table_a(keep=i id id_2 category) table_b(keep=x);
36               declare hash hh_bew (dataset: 'table_b');
37               hh_bew.definekey  ('id', 'id_2', 'category');
38               hh_bew.definedata ('x');
39               hh_bew.definedone ();
40             end;
41         
42           set table_a(keep=i id id_2 category);
43           by i;
44           if hh_bew.find()=0 then sum_x + x;
45           if last.i then
46             do;
47               output;
48               call missing(sum_x);
49             end;
50         run;

NOTE: There were 1221506 observations read from the data set WORK.TABLE_B.
NOTE: There were 308097127 observations read from the data set WORK.TABLE_A.
NOTE: The data set WORK.WANT_HASH has 5549 observations and 2 variables.
NOTE: DATA statement used (Total process time):
      real time           2:44.66
      user cpu time       2:35.29
      system cpu time     3.96 seconds
      memory              134044.34k
      OS Memory           153324.00k
      Timestamp           03/07/2024 11:27:16 PM
      Step Count                        31  Switch Count  249
      

51         
52         /************ temporary array direct key lookup ************/
53         %let max_i = 5600;
54         %let max_id = 55000;
55         %let max_category = 22;
56         %let max_ID_2=1;
57         
58         data want_ARRAY(keep = I SUM_X);
59         
60           /* populate array */
61           array XX[&amp;amp;max_id,%eval(&amp;amp;max_category*10 +1)] _temporary_; /* instead hash table */
62           do until(eofB);
63             set table_B end=EOFB;
64             XX[ID,CATEGORY*10 +input(ID_2,1.)]=X;
65           end;
66         
67           do until (EOFA);
68             set table_A end=EOFA;
69             by I;
70         
71             if first.I then SUM_X = 0;
72             SUM_X + XX[ID,CATEGORY*10 +input(ID_2,1.)]; /* direct keys addressing */
73         
74             if last.I then output;
75           end;
76           stop;
77         run;

NOTE: There were 1221506 observations read from the data set WORK.TABLE_B.
NOTE: There were 308097127 observations read from the data set WORK.TABLE_A.
NOTE: The data set WORK.WANT_ARRAY has 5549 observations and 2 variables.
NOTE: DATA statement used (Total process time):
      real time           57.70 seconds
      user cpu time       52.67 seconds
      system cpu time     2.46 seconds
      memory              96194.21k
      OS Memory           115820.00k
      Timestamp           03/07/2024 11:28:14 PM
      Step Count                        32  Switch Count  102
&lt;/PRE&gt;
&lt;/LI-SPOILER&gt;</description>
      <pubDate>Thu, 07 Mar 2024 12:36:49 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919294#M362107</guid>
      <dc:creator>Patrick</dc:creator>
      <dc:date>2024-03-07T12:36:49Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919296#M362108</link>
      <description>&lt;P&gt;In fact, why do we have to limit ourselves to 2 dimiensions? &lt;span class="lia-unicode-emoji" title=":slightly_smiling_face:"&gt;🙂&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data WANT_OPTION_B_array2(keep = I SUM_X);

  /* populate array */
  array XX[&amp;amp;max_id.       /* 1 to 55000 */
          ,&amp;amp;max_category. /* 1 to 22 */
          ,0:1            /* for ID_2  values 0 to 1 */
          ] _temporary_;
  do until(eofB);
    set test.table_B end=EOFB;
    XX[ID,CATEGORY,ID_2]=X;
  end;

  do until (EOFA);
    set test.table_A end=EOFA;
    by I;

    if first.I then SUM_X = 0;
    SUM_X + XX[ID,CATEGORY,ID_2];
    
    if last.I then output;
  end;
  stop;
run;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;With 3, we not have to do any additional calculations.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Bart&lt;/P&gt;</description>
      <pubDate>Thu, 07 Mar 2024 12:58:37 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919296#M362108</guid>
      <dc:creator>yabwon</dc:creator>
      <dc:date>2024-03-07T12:58:37Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919299#M362110</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/35763"&gt;@yabwon&lt;/a&gt;&amp;nbsp;LOL. Not sure why but I had so much in my mind that we're limited to max two dimensions that I didn't even try.... Learning new things today &lt;span class="lia-unicode-emoji" title=":slightly_smiling_face:"&gt;🙂&lt;/span&gt;&lt;/P&gt;</description>
      <pubDate>Thu, 07 Mar 2024 13:03:34 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919299#M362110</guid>
      <dc:creator>Patrick</dc:creator>
      <dc:date>2024-03-07T13:03:34Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919300#M362111</link>
      <description>&lt;P&gt;Well, you did figured out that there can be 2 dimensions. And me, I didn't step out from 1 dimension level in the first place &lt;span class="lia-unicode-emoji" title=":grinning_face_with_smiling_eyes:"&gt;😄&lt;/span&gt; &lt;span class="lia-unicode-emoji" title=":grinning_face_with_smiling_eyes:"&gt;😄&lt;/span&gt; &lt;span class="lia-unicode-emoji" title=":grinning_face_with_smiling_eyes:"&gt;😄&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Bart&lt;/P&gt;</description>
      <pubDate>Thu, 07 Mar 2024 13:09:02 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919300#M362111</guid>
      <dc:creator>yabwon</dc:creator>
      <dc:date>2024-03-07T13:09:02Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919331#M362116</link>
      <description>&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/35763"&gt;@yabwon&lt;/a&gt;&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/12447"&gt;@Patrick&lt;/a&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Guys,&lt;/P&gt;
&lt;P&gt;Thank you for inspiring solutions, and just as an FYI, on my machine, Single level/dimension array approach was the fastest when compared to 2-Dimensional &amp;amp; 3-Dimensional array approaches. I wonder if you had similar findings.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 07 Mar 2024 16:02:04 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919331#M362116</guid>
      <dc:creator>AhmedAl_Attar</dc:creator>
      <dc:date>2024-03-07T16:02:04Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919335#M362118</link>
      <description>&lt;BLOCKQUOTE&gt;&lt;HR /&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/13868"&gt;@AhmedAl_Attar&lt;/a&gt;&amp;nbsp;wrote:&lt;BR /&gt;
&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/35763"&gt;@yabwon&lt;/a&gt;&amp;nbsp;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/12447"&gt;@Patrick&lt;/a&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Guys,&lt;/P&gt;
&lt;P&gt;Thank you for inspiring solutions, and just as an FYI, on my machine, Single level/dimension array approach was the fastest when compared to 2-Dimensional &amp;amp; 3-Dimensional array approaches. I wonder if you had similar findings.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;HR /&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Could just be a result of re-running and getting benefits of caching.&amp;nbsp; Run the two in opposite order and see if the the difference stays the same.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;If so then&amp;nbsp;I assume it because of the reduced number of checks that SAS has to do to make sure the indexes are in bounds. Doing the simple multiplication and then just checking that the result is in bounds is probably faster than checking three index values. Especially since it probably has to do the multiplication anyway to index to the requested location.&lt;/P&gt;</description>
      <pubDate>Thu, 07 Mar 2024 16:10:28 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919335#M362118</guid>
      <dc:creator>Tom</dc:creator>
      <dc:date>2024-03-07T16:10:28Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919357#M362125</link>
      <description>&lt;P&gt;Cześć Bartku,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Thanks for the plug.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Key-indexed search / aggregation always wins speed-wise if there is enough memory for it.&amp;nbsp;&lt;/P&gt;
&lt;P&gt;If not, an array-based hash table is the next fastest option coupled with a drastic memory reduction. I'd just use the simplest collision resolution policy, the linear probing, and set the hash table size at approximately twice the number of distinct keys. Code can be adapted almost verbatim from our (with Richard DeVenezia) last year's SESUG paper "Hashes From the Ashes", Section 2:&lt;/P&gt;
&lt;P&gt;&lt;A href="https://www.lexjansen.com/sesug/2023/SESUG2023_Paper_203_Final_PDF.pdf" target="_self"&gt;https://www.lexjansen.com/sesug/2023/SESUG2023_Paper_203_Final_PDF.pdf&lt;/A&gt;&amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The hash object is a great tool (it would be funny if I thought otherwise) with gobs of functionality compared to array-based hashing but the latter can be faster/lighter at specialized tasks. You know, at times one needs a dedicated blade instead of those included in a Swiss Army knife.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Gorące pozdrowienia&lt;/P&gt;
&lt;P&gt;Paul D.&lt;/P&gt;</description>
      <pubDate>Thu, 07 Mar 2024 19:46:07 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919357#M362125</guid>
      <dc:creator>hashman</dc:creator>
      <dc:date>2024-03-07T19:46:07Z</dc:date>
    </item>
    <item>
      <title>Re: Join and aggregation of large tables - is there a faster way?</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919391#M362136</link>
      <description>&lt;BLOCKQUOTE&gt;&lt;HR /&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/370514"&gt;@Bernd_S&lt;/a&gt;&amp;nbsp;wrote:&lt;BR /&gt;
&lt;P&gt;Hi,&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;a href="https://communities.sas.com/t5/user/viewprofilepage/user-id/35763"&gt;@yabwon&lt;/a&gt;&amp;nbsp;Thank you very much, that is exactly what I need. I also didn't know and didn't expect that the use of an array would be so much faster. I can make ID_2 numeric.&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Arrays are ALWAYS faster than hash lookups, because arrays use direct key indexing.&amp;nbsp; The array index effectively points directly at the location of the content.&amp;nbsp; &amp;nbsp;But a hash KEY needs to go through a transformation to find its location in the hash object (but the hash transformation will be faster than the analogous binary search for a key in a sorted list).&amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;But arrays can't do this:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;You can index (i.e. definekey) on character values..&lt;/LI&gt;
&lt;LI&gt;Dynamically grow the number of dataitems in the object.&lt;/LI&gt;
&lt;LI&gt;Retrieve a dataitem of multiple variables with a single hash method call, whereas the array analog would require programming retrieval of the i'th element from each of a set of one-dimension arrays (or multiple columns from a given array row).&amp;nbsp; The same relative advantage exists for adding to the hash vs adding to arrays.&lt;/LI&gt;
&lt;LI&gt;Dynamically create the content of a hash object.&lt;/LI&gt;
&lt;LI&gt;Dynamically free up memory used by a hash object.&lt;/LI&gt;
&lt;/OL&gt;</description>
      <pubDate>Fri, 08 Mar 2024 01:05:40 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Join-and-aggregation-of-large-tables-is-there-a-faster-way/m-p/919391#M362136</guid>
      <dc:creator>mkeintz</dc:creator>
      <dc:date>2024-03-08T01:05:40Z</dc:date>
    </item>
  </channel>
</rss>

