Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1iq5JR-0005oZ-Un for pgsql-hackers@arkaria.postgresql.org; Sat, 11 Jan 2020 01:11:38 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1iq5JP-0000ry-Md for pgsql-hackers@arkaria.postgresql.org; Sat, 11 Jan 2020 01:11:35 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1iq5JO-0000om-Tx for pgsql-hackers@lists.postgresql.org; Sat, 11 Jan 2020 01:11:35 +0000 Received: from mail-wm1-x331.google.com ([2a00:1450:4864:20::331]) by makus.postgresql.org with esmtps (TLS1.3:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.92) (envelope-from ) id 1iq5JL-0007R5-Ea for pgsql-hackers@postgresql.org; Sat, 11 Jan 2020 01:11:33 +0000 Received: by mail-wm1-x331.google.com with SMTP id 20so3845476wmj.4 for ; Fri, 10 Jan 2020 17:11:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=2ndquadrant-com.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=IIPW/XP8ViCpNq6FqgCr1EJ4/I4oDLWOvO7wcBUiN0s=; b=ToEtICCmc08UmHYzEoP6hp3zbAQrzX+w17fL1kSGqPoTIasnKm/8enUcFQ3E0j+lfm cEFHny+3ZiG04szVdeMgNXOYiHaLZi99SmTWAszzYhiWyWFIdxcOlRx7awXm0wMHjDEY NeR46QHczljQSFp7uXpmXjegAC+3qOntjw1nBOgj3n27F3EAfv2uuruGnbFpOvQy1HqS XaPN5XWm7zNXNMMjGP0/BdEnqU9YJQp4KQWMK492lG0i2JWGH1EOY6q/QNy6/ccx1+qG BDFGfmk6Kxg3gfpI0c803L19UwPFm7oeFRoDndZHIWujMmtpi6ZKo/gMXfwTbTAdmHhc f7iQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=IIPW/XP8ViCpNq6FqgCr1EJ4/I4oDLWOvO7wcBUiN0s=; b=O5gksIhVvI589R4VedkxXuGthkPvrcwUX3uQyqdcxLE40ev/uKS81LzcuSYUSrtC+t P+YVcLhz7zn5574gePww1iyjnECiFuRkvuX8egysW/03d7C6+a43jwIg5lvbsrq+e7wm D9EU9iP7Kqv16N2TdK6cSW7HLCgHxAUGOeuMzjskGKEPNWLeHnOaJGckw5RdVAjl5JRs J2erAIzVLYsBmfhKqyJLqQzVigyjAy0lpFqDOLWlCmol0c2PSRcqLlXV6a2QHZcyiYb+ XW9ugvjciloSPb5T236cvKIt3/ZBntTKmGD+E+9hE2rppMXs+nkT10Hvhz7Rsy1fs/Ax qrQg== X-Gm-Message-State: APjAAAVs1lHKssVodSZirOqC0cdZS3h60itxw3BammCRMayQnDHuXm+I haD/MZ4oW9rIPztNvEYJXhWyng== X-Google-Smtp-Source: APXvYqwzndVz73vjj6bpa4TRK3S357XVTbeuoSiM/cnhBX7UNzbuuAGfqI3Rzf0gptWQXqlzNqWPqQ== X-Received: by 2002:a7b:cd11:: with SMTP id f17mr7220470wmj.48.1578705087954; Fri, 10 Jan 2020 17:11:27 -0800 (PST) Received: from localhost (ip-86-49-253-92.net.upcbroadband.cz. [86.49.253.92]) by smtp.gmail.com with ESMTPSA id i16sm4517747wmb.36.2020.01.10.17.11.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Jan 2020 17:11:26 -0800 (PST) Date: Sat, 11 Jan 2020 02:11:24 +0100 From: Tomas Vondra To: Antonin Houska Cc: Alvaro Herrera , Richard Guo , Tom Lane , Michael Paquier , PostgreSQL-development Subject: Re: [HACKERS] WIP: Aggregation push-down Message-ID: <20200111011124.efacqhdsptc36pm2@development> References: <20190904202339.GA13644@alvherre.pgsql> <7087.1567663858@localhost> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="l2egltguwm3evkqb" Content-Disposition: inline In-Reply-To: <7087.1567663858@localhost> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --l2egltguwm3evkqb Content-Type: text/plain; charset=us-ascii; format=flowed Content-Disposition: inline Hi, I've been looking at the last version (v14) of this patch series, submitted way back in July and unfortunately quiet since then. Antonin is probably right one of the reasons for the lack of reviews is that it requires interest/experience with planner. Initially it was also a bit hard to understand what are the benefits (and the patch shifted a bit), which is now mostly addressed by the README in the last patch. The trouble is that's hidden in the patch and so not immediately obvious to people considering reviewing it :-( Tom posted a nice summary in November 2018, but it was perhaps focused on the internals. So my first suggestion it to write a short summary with example how it affects practical queries (plan change, speedup) etc. My second suggestion is to have meaningful commit messages for each part of the patch series, explaining why we need that particular part. It might have been explained somewhere in the thread, but as a reviewer I really don't want to reverse-engineer the whole thread. Now, regarding individual parts of the patch: 1) v14-0001-Introduce-RelInfoList-structure.patch ------------------------------------------------- - I'm not entirely sure why we need this change. We had the list+hash before, so I assume we do this because we need the output functions? - The RelInfoList naming is pretty confusing, because it's actually not a list but a combination of list+hash. And the embedded list is called items, to make it yet a bit more confusing. I suggest we call this just RelInfo or RelInfoLookup or something else not including List. - RelInfoEntry seems severely under-documented, particularly the data part (which is void* making it even harder to understand what's it for without having to read the functions). AFAICS it's just simply a link to the embedded list, but maybe I'm wrong. - I suggest we move find_join_rel/add_rel_info/add_join_rel in relnode.c right before build_join_rel. This makes diff clearer/smaller and visual diffs nicer. 2) v14-0002-Introduce-make_join_rel_common-function.patch --------------------------------------------------------- I see no point in keeping this change in a separate patch, as it prety much just renames make_join_rel to make_join_rel_common and then adds make_join_rel(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2) { return make_join_rel_common(root, rel1, rel2); } which seems rather trivial and useless on it's own. I'd just merge it into 0003 where we use the _common function more extensively. 3) v14-0003-Aggregate-push-down-basic-functionality.patch --------------------------------------------------------- I haven't done much review on this yet, but I've done some testing and benchmarking so let me share at least that. The queries I used were of the type I mentioned earlier in this thread - essentially a star schema, i.e. fact table referencing dimensions, with aggregation per columns in the dimension. So something like SELECT d.c, sum(f) FROM fact JOIN dimension d ON (d.id = f.d_id) GROUP BY d.c; where "fact" table is much much larger than the dimension. Attached is a script I used for testing with a bunch of queries and a number of parameters (parallelism, size of dimension, size of fact, ...) and a spreadsheed summarizing the results. Overall, the results seem pretty good - in many cases the queries get about 2x faster and I haven't seen any regressions. That's pretty nice. One annoying thing is that this only works for non-parallel queries. That is, I saw no improvements with parallel queries. It was still faster than the non-parallel query with aggregate pushdown, but the parallel query did not improve. An example of timing looks like this: non-parallel (pushdown = off): 918 ms non-parallel (pushdown = on): 561 ms parallel (pushdown = off): 313 ms parallel (pushdown = on): 313 ms The non-parallel query gets faster because after enabling push-down the plan changes (and we get partial aggregate below the join). With parallel query that does not happen, the plans stay the same. I'm not claiming this is a bug - we end up picking the fastest execution plan (i.e. we don't make a mistake by e.g. switching to the non-parallel one with pushdown). My understanding is that the aggregate pushdown can't (currently?) be used with queries that use partial aggregate because of parallelism. That is we can either end up with a plan like this: Finalize Aggregate -> Join -> Partial Aggregate -> ... or a parallel plan like this: Finalize Aggregate -> Gather -> Partial Aggregate -> Join -> ... -> ... but we currently don't support a combination of both Finalize Aggregate -> Gather -> Join -> Partial Aggregate -> ... I wonder if that's actually even possible and what would it take to make it work? regards -- Tomas Vondra http://www.2ndQuadrant.com PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services --l2egltguwm3evkqb Content-Type: application/vnd.oasis.opendocument.spreadsheet Content-Disposition: attachment; filename="pushdown-agg.ods" Content-Transfer-Encoding: base64 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 GgAAAENvbmZpZ3VyYXRpb25zMi9zdGF0dXNiYXIvUEsDBBQAAAgAAPm7KlAAAAAAAAAAAAAA AAAaAAAAQ29uZmlndXJhdGlvbnMyL3Rvb2xwYW5lbC9QSwMEFAAACAAA+bsqUAAAAAAAAAAA AAAAABoAAABDb25maWd1cmF0aW9uczIvcG9wdXBtZW51L1BLAwQUAAAIAAD5uypQAAAAAAAA AAAAAAAAHwAAAENvbmZpZ3VyYXRpb25zMi9pbWFnZXMvQml0bWFwcy9QSwMEFAAACAAA+bsq UAAAAAAAAAAAAAAAABwAAABDb25maWd1cmF0aW9uczIvcHJvZ3Jlc3NiYXIvUEsDBBQAAAgA APm7KlAAAAAAAAAAAAAAAAAYAAAAQ29uZmlndXJhdGlvbnMyL3Rvb2xiYXIvUEsDBBQACAgI APm7KlAAAAAAAAAAAAAAAAAIAAAAbWV0YS54bWyNk8tu2zAURPf9CoHJluJDriITkgJ00VWC FKgLdGfI5I3DliYNkoqcv4+ertN60aWGZzhzSaq8Px1M8go+aGcrxFKKErDSKW33Ffqx+YoL dF9/Kt3zs5YglJPtAWzEB4hN0lttENNShVpvhWuCDsI2BwgiSuGOYBeLuKTFGDQpJ6Pt7wq9 xHgUhHRdl3ZZ6vyesPV6TcbVBVXyzB1bb0ZKSQIGhoRAWMrIwg4N/7fUwF5Wcs6dgwZ8Kj3G cUpXZPpe6L1XylwboGcz0jdsYoNfNXQ3KJnHvzhwjurldIcadTmWkR6a2BO4N0PNKaeYMszY hlLBM5HdpZQXlLN1TktyxVEqKa5YMyY+0zSnBWerrGAlWbApFZSO/cVj1fpxr/rbpnhk9Psc 8c/yR5d8kwZCnf9Fz/LE7sFCb3a+ftA7D0/j4CRPeVqk/PZB2/a0/Vnk23yVXADbo3e/QMb+ RG+/tNoozOeQP/tN+58faIh9xRC1TEY9NjsDWLrWxgpxNIkSjFm0O8Zm1e2GqEWniNQl+XBB 5NrPUL8DUEsHCCTK+rWZAQAASgMAAFBLAwQUAAgICAD5uypQAAAAAAAAAAAAAAAACgAAAHN0 eWxlcy54bWzdWm1v2zYQ/r5fYajAsAGTJdltGnuJg21dtgFtULTp9rFgJEomSokCRb+kv35H UpSpN0dx4qSbUzQx+dzx7rkXkrLPLrYpHa0xLwjLzp1g7DsjnIUsIlly7ny6vnRPnYvFd2cs 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 YycnIOMzakWl+0oE5wDRDiXlpDfGtiBnCCPTdlXdLRjroC7t8XIXYLJzdVB0bJh4qOseAmir aroEaJgKwdl2FCROqPmYAZ9b5ylEUDodAYiJJVIOx9z/oLIuCZqWPGD3QIrtVQdiqC9iSUBU xp14Se0BMpUgxVBeBDyd8ajNE+mVrrfFHHuPxnY5jhBpLZ6cUso42OXZ8naOsNAgkHp5aoku Dl4/jGKThsf4HO5G/Pvx219QSwcIn3X6iTEBAAAsBAAAUEsDBBQACAgIAPm7KlAAAAAAAAAA AAAAAAALAAAAY29udGVudC54bWztfWuPIzty5ff9FYW68MIGViy+H723rz/srGwDM8bCHi8W MIyBupTVVzsqqSypX//ewWQy66VsBVlJlqqkHkz3rdJRZpBKHQaDcSJ+/fvvt8uLr81mu1iv Pl4yQi8vmtX1er5Yff54+W9/nk7s5d//9t9+Xd/cLK6bD/P19ZfbZrWbXK9XO/j3At692n4I r368/LJZfVjPtovth9Xsttl+2F1/WN81q/iuDw/RH9p7hd9sdz+W6Le34Ifv3jXfd9g3e+yj 984+4e/cgh++e76ZfcO+2WNhUh++/WaNffP37XJys4ZZv72b7RZPrPi+XKz++vHy993u7sPV 1bdv38g3Qdabz1fMOXfVvtobfN3j7r5sli1qfn3VLBt/s+0VI+wqYm+b3Qxrn8c+NGn15fZT s0FPzWw3e/ap3m2aLUBguP7BxF3o4XsePV9fP6Ofrq+fB6b5+vfZBv2cteDHj4qY4x8VMX/4 3tvZ7veBz9de/QlebP/60x/vn6vNLfZeHvtoqq43izv0MAP64fvX63Vvqn9D+LK35nJK5VX4 +QH620/h3zaLXbN5AL/+Kfx6trzuZ3x9u2/SAMeuADFpvvpHvv8S+YnYDryBX4WXe/B2Pnjp //enP/7r9e/N7ewevDgMnixW291sdT8zG/8hDI5UXW2au/Vm10/MDZ584dPivW2/726Xw9Th X43Qz5v5fC8UzBFXQCPwJZ58XTTffnnErT9/HtxVC3rIpz99A6NXHtN/JeHjvif/zed+fbpZ f1nNAw2EyWi+3zWbhX9ptmzf9uHRFR4+wct1xiW7Ne3BFR4R/aJZxm9/P6S9l1mvJ7dbeBjg oV/ffXjw7sfrxub2O+5y/kFfz2+eXvHJl/56uxW7fZ/tn//lyr828csmLAzdnR64C/zyt+gb BC7YXvW/uAEfYXIzu24m8+Z6uf3t18Dx/a8vws/e7o+Xf1zAgtFO78W/zlbwTQMijtDbxfLH x8v/Prtbb//nE1z45eXFo0t7/ORzs4KJALrYfltst48Qd4vdNRDq19lm0T59Vz837Q+b9WLe 3u3iD83X2Wr2Gd44aOBeNMbMH9tdczuSndPZcvlpdv1XjJURO5qNV0Off/f72ZfdGpa0xfWk vU7/YLR/PxrR9Zr1N+vMb/kCVujll9vVZXznw19O7uA5bza7RbO9uFl/+LRpZn+dfGrgkYcL +lvHK3bwb4u5X12VIFrf7Vr7H5jzM9t4LduEJi7RNlHLNs0USbRNVrONE+bSbFPVbJOEshTb NkPfhc362xPD4DcPrQov+V/+3iw+/w5Ezzix/uY/N/jLtpms73aL29ly8vDdu82XJsXuge9J jt0iTFoNu3ez/fMdf3kLW5ZmM7mbfW4mHf82N7Mvy92TQT0YUNg/zhfbu+XsR2dPdzXv58Lu cHK7nsOVlpvJ7tNzU8Ou6gNc7tqv73Dj52b/M2OXPTL8c9H9BCzczgnc/boBVxc+l+Cp3C5W kz0vdm/zr3r34TOMdr74vNjBq8wb173ufYPf/ubXq4c/9j89tfUn371miOub5TK+cjfb+OhD +0M36/9n8XW9+wunf/mzR/v/mHp/6el3FS7y9Ju63sz9HpUSByRxsV0vYUX8hbZ/EiijGVoG Us3+XzOY4/XmR3xT61A/fMs/U+ygJp/Wu53f/qzWq+bywe+Xzc1uYMQPUJvwfTkE263vXj57 QwvVacxee4eE2RpaOo9htg4N+PVnb2hxf8XZSx+EzhrE/rXpqVnda8Dgk9ly8Xk12a6/bHxg 92bxPV5809w1sz4ADC/Nltt+GfvqLwR76vD2j5e3i/n84cYFLJt93szufn8yGfe39EP0e9WU KTHH97mW+VY8JaSsb4Edabb+72x577+8Ot3unZqXLk7udKYq9Sli9Fjn5vi+cWwsz3asucoY wjF7ubhP/OlH2X3CvN1SjuxpsLHc2krM8ZK5eSnJsrGc2jcwV8nP0Vgu6yuxbNW5yvOM3+Rz NPSde+DAP7boer1cA+3/cnPTX68Nz3/rYmOf1sv5o7h+eGEy2y5mq+GX/Un5svneAVI+rLF8 9jfwYcUH+e18OEe7RTg036/g2x3tHgE3VzUZmuftGWLsYnBuGLv/eu29b57/jbzv1eCxZvfC p/X8x/0p+d2mmc23vzfN7rdfw4GAz0H4smzPtCfbZufPAeJZwf01bxar+WQ5+9Qst33MJWD8 ccem+QxX2Eya7z4Fyh/O70N9Wyzn17PNfHt/FhJebP/ugGFs35v1Kr714Zj9qcijd3WnYHug 7eFtd+QRZjI8tI8wjXpixc+ux0e+nhj5ejJeLxx+dNDtJITMmnl7qnLwjuGpqnjL+Jzj76rK 3XWz/rbnlv7w84l1cL09wP47e8A+8Wy0+6/Xxltj2otn6Mnuxx38frvbwNf08iLmD+17ba8J 27vZavVohjoADPzBq+1w/YXvfts2m8Vs+etV9+OvV0/N7nlk/bXZNPMJaoLezPB9yHi5bPIm 4M2McnvXNPMvd7mDfISGm4z6nWpPZvOmpx/fCjGy4kbMj8GI//zSbH683BDzYkPg7SPMB3+5 HSM8G6c7Gy+8HXpxGe+WKEIvTGj7P6eb5Xq2e/wKkHTc/OwbW3hHP7QO+/IHKc0+rG2l7Ep7 4JbN9e5izshi/j8u5rz9Z/vl9m9v2N9d3GzWtxc3M3j95uL/rxeri/ni9i8zAF+sVxd/277n 4mP45V8W87+7x3yCKwUMv8d8ajGfN+svdxeffjy65ctnwiZ8QpJRIhmXuM8pokegI4E3UjtK uBIoEzts1UlUVBNrPcEiDIzgulPo78qY1mgTPXiE7ySNTqZP6/+ynH28XN98+Pjv5H+L/7j6 d/IH8R97h3Cfmfd0HPD4WSeccU4qprQ0+wf04AL9qKQlTv5NwTH9QzumacaYnLPSMaWcUcbZ hDE5R6z6+ZgKr1YCsd3G7nT2P8/5DJ5L3Y9p+eVPjMN/Tx2zRFiLo5IIHoFKZAKVaEYk93F4 DJV04KqTKJggxhncmhbBdSfR39UKgfucI7gkH8uWj2U6d2nGBOPUOCapcHjqggeDiaJ03A5p mjwkRsBNZjAaq4UEZsYPCdxYQtmZjkem43RPuirbMK4c0QrpW/XounyjLVAIPM84H7oDV51G yRVx1uFmMYLrTqLk4BcbiSPtCC5J2qolbZVO2kpymD3tGFUUlmg8xSlJuCvK2u2Ypsljallb CiGkcIzrgc9okLUPbAxOlLUB1QYl2n9r0feDm9blcWkZ0RLp2PboyjzuKLiCGmdjBFedRiVg P6uQK00EV97BCIaPeUVwSR7XLY/rjGCI1lxLYQVzzpgE0pOa6LLedzumafKYWh63WkoLA1NG JfL4gbXplHl8jGhIbU52ihJuhx7sp+GQDlw7HGLBJUI6hRFcNxwCzjK487hQQ8BWDoZ4V5kr nOsfwSX52LR8bDL8amcpF5o7qg2wWIJf7YilRfm4HdM0eUyBj6mymjLBZMJWoeVje+bjsfk4 w5+uHA9xinCJjGH36LqUY1pnQeFcwAiuGw8RjjCNjYd04MrxELirZhwZD+nAJXnbtrxtc+Ih VDGq/fm21G7gqRiIh9ADB3Av5O12TNPkMXneBgY2ljFG1dBBwxBvswNr0SnydiZfV958O+I0 ktYiuPbmG+7KkM5eBNddwKwklg/sPJ8uXwFbdwrbmyrkpxzBJXnXtbzrchIfnKPGGGa1FTLB X3bwXJSNQ7djmiaPKZweaimNc0zIgV3XoL/MX5l3sawqE5Cvy78Yf3mEry9NCGpQRQxsD3FB jQ48gokqzURrkJ5dBNedRUEtuLwWN4sRXHcW/V05Q4Y1ArYkSzPa0jT8k5cRwZy0VlGd4B5j MiJeyNNhVNPcUSnBNLc+geWdMnViOjk6l/ycsP06CdvgJxHBkatHj66bbQy3FcQZZPCiR9ee SEWAzLBedId+hYnkkqM/7YAuuoqwsIqwLG/fMgF+MXXaDp1hD3n7ByLJL11FWFhF8kZFqRHC cEeZSciA9KM6x1neVfK28SFOHOtFcOXoi3LEUGzqQweunLytCRVYv74D107eVkQaJClHcFFO 5oGTeUb6NnVOKSAwprRmCekW2vvPZTmZB07OGBUsNJw6aqlWhtmEUXlBzWt79u+Pk48+g9tK f1yCPbHs0HVJxzrPI7i1pcNWP6+0An9cCdjap5WWCIbN3u7ARVk7aCBZhmBQOyMZVRrWP6NT JCoaVvSyIsgwqmnOqJw/jYKlSFJulEs4snReUnFm7aFMk5PJ4LbOEGaREdceXfvwzt8W+CXB SEDXnkgNe1MkV/bo6hOpiFHYPKOILsroQUXJMmSU/iTUAvcpA16rSz02LOyIByVl5rCEU1YZ I6QTaY74IbX+KVP620zm9kdcuLyKDls5OCJ9oz2KTE3pwJVTuQ2e8iK4djK3Ac8ZGWGK4KKk HFSSLEcmqY3QFkiZMikTvGyli3vZQSaZMyhYZ7RwVlGnhaAJCd0+NqLPlDw2JR99Prdg8MGb oef/qZ8V0bWjI5wM6S2eBUc8tG5sRPma1QNftaeRh4CtHBtRFBYz5J4kgouSdpBEsgxNpDZa GsGVP5HjLCFZRZuDUYSXsnYQReaMyjlDmVPSV4myPO2U0ZxPGd9mNrdkhBqLPKzrwLVdZkYY Q5ZaiuDKsQxFLEdnUARw7UiGItphE85bbFHuDfJHlqcVpIbDY8iN46lBjMJ5gkEAmT6qEMRg nEtLfWWRhGH5IMYBlf3R5AmeM7pfkNHNLeEGWc0tgitndPu7uiFp2z4TAVw5o5spoiRS1hLB lTO64a5M4RM/AFuUqYPgkWWpAynlsNRJKd1QDuRrhZuD5DF9VG1sw4DXb6WEbahJjG28tla9 UEZ3Qnnwc0736+R0O0GJwMptenTlVGR/W0exqsOIrj2RjMDGH+nsR/QrTCSTSG+hRxddR4KA k+WpHbnRnGn439BOdXAdKVuBKoxqmj6q1uPnlsLjS5lhKUWojsHjP8JoyxvO6TYCvHWKdO07 cOUYjGNEKmT0O4LrHlsaWLEELv7dYSsfWhpGBLbYSgSXZGQetJo8WdXoM7qNaYtQaTZ42r43 /E2JMUUJOQxqmj4ov8wAH0vFvFJzKJY3tMzw13bs3x8hH3tCtxAOvAtktKNH1+UcpxnR8FDj VpYOXPf8gQtCsSW5I7jy2gd3FRZbbbYDFyXuII/kGUJCA+xmtbHCSKeHnot9JAfr0SHRykuZ O8gj00fVbhAUbA40t8qq1LLc53STc1K3sz4VdEjk8Gy73KErn+A5B99frJa8A9efRmuQsese XX0awbWWaCM7dFE+D9JKnixCbJmvFbsrJVWqz3qoIcFL+TxIKzNHZYQ1wikzpPYaHNSB7cUp 0/lbTOhmlHHCHDbcGtG1oyOcSIsUTkZw3eiI1cRiC5FEcOX4iDXEYD/oCC5Ky0E7yTNUhuCG +r5eymnNbEpsV1miykasw6im6aNqAySScuE4UzolqbsNkJyFNieY1W0sQUslO3DlAIkCHqED qa7P9EIttm54REiikTPYYSsvfUIRQbHxmw5clLWDPpLntJl04Ogbp5Xg2piEHDztiDwQRngp awd5ZPqo2hrd3BlhnKWDaUWDNbrP54xvM6tbacLsUBXNZyWYArgycSjle+IiiaMDVw5nSKK4 wQYKArh2MAPuKpGFrCK4KPsGISTP0gw6QalT4Ad42eCo+RAvZd+ghEwfVaj/So0fFWdDj9KR 9vmVI7LvOZ/7edKHIY4hO0FGcOV8brirRRbo6LCVs7m9HknhvPcOWzmXW7ZpHGgDAVuUnYPi kWdpA326muZgpbNDWaSv00UhjGqaPqqWnR21TggtpUvtO/a6fSBTM7STkrQL5mkPWYg17pw/ /jr548JZWIPw+S4RXjfxWRtgUS2QuZQ9uupUCm0sATJFVliJ6LoTCbfVRA00LHhuoscWXbmC XpRnKCulZU5TTh0XSqfUzpaW8LIqpDCqac6o/G5JWV/Py5egTdwtnWPx7yl7nPlKrAzXezeC K8d6tBHEGI1tYNyhq04jF5wRPlQ+7omJEVx3Grmve6M58hS3Rxfl5aAO5Rk6Ss0M9dpQ2PP4 tr9JVcEPVRt5KS8HdWjOqNoolmZScU7Z0MHSWdVzTiIPXjWXThKnkK0q7+F1iUcbIwkfbKfy zKvu0HUzXJj1p3BDJZ2fCec7dOUcF39bnmQkH8XInzB40GXyDAWjkl6TaYT0bDe0uA90NOaF k8mDLjNnVD7S5RvtCC0ZHyqolhnpOlEG/3pSyeTScF8GGlsOqofX5nQhiTXIKESPrp21yMEr QpaF7NG18xa1ItRhq9FGdElOF0HZKTKUnVIZoYSRSlOXlFEuVel6tGFU0/RRBYGQz8l0VJuh D+osEDqNjHJnlCVYrU8EV46XGGqJoth4SUTXjZdIX31FI23s0ZUjJlJwX7AJa2MLLsrMQbop MqSbykpnjFNSOQdud1pOedl4SRjVNH1ULTNboQy43JrL1BPYs+j+BHPKmaVE47PKI7y2d80p sRzZ7q1H1/WufYBYComsSBLRlb1rf1uhkQWKe3RRDg9yTZHRM1JRZz3VwR8KZJ7A4bR0Fk0Y 1TRnVF1fIQXzLlPCQJg6j6fI4W8iw1xwcCvQmseIruxHJ/WyUeM1s0la0CSFuyJrtPToynnm PjlRW41ddDt0URYO6kyR1QPS+eqtEqjYWJnAwuV7xIdRTdNH1XrS2lmugYZNSvr8UajmzxXE M7/EKRnnVDhf9g7ZOz6iK+ecUyA4K7B1ziO67kxybgT4wrioQsDWncX2poYZZHAmoovyddBl iiwFI2VaMwZcDVYmMlvZc8YwqmnuqLgGx8gJl5IoUk4ZxMfn68QsdXSG+jkL/HWywOFrKBJa 3fTwEehPpzxKWhqfn4etGhPhtSeT+g0Htkp3D3+VyWTISP89vOhqEnSmIkNnqiW1PvxifZez FOLV8qDm56WrSdCZ5o2KUedg5wXbGps2KPa6MtOjDMG85XRwDf6mw1YTj+jKgRllODEWJy+J 4Nrp4Ipwjk4Hb8G108F94hDDnm5GdFFaDgJTkdNSk1qmGBPWSEmH8mEHaooXrkwbRjVNH1Vo XcG48XXAGE2V/x8Y1ZmX3186uKW6LdiDTAeP8LrEY622RClkE/seXfdwkwvr2xRg29h36MqH m1wywilyA9CjizJ4EFqKDEmidlwJarm2RjGREKfRjvCyTZHDqKbpowoJKpQp45g0LjX4VCRB JSFMc5wM/vWk0sENt4ZYrG4+okcgIpO0x3cuaY/fwatPpSXCIDNW7uH1JxN8UodcH+/hRXk9 CDVFllDTWistsJ91PKVKimYwrLK8HoSamaMSVjNYTrkaqtAzNKizfv59ZYQrA260GOoc8rwM bEBXDpnArpgIiiwY1qMr54QzA9tWpLyxR9fOCYfbOpVipEcXJeegwRQ5GkwtpWaibf8wFPPb m1CoiSzscwcJZvqgQlcLK412Vquh+nO5XS3O5Pwuk8J9BsNQ1tPznPCArh01EQa8DmS4tkdX TgkXyh+EYrOtO3TtlHChCVMMbWRAlyRwGQSXMqeVpqFWUaqN1nZwUdrriJrSx5FhVNP0UXUt m6WWgltBE/pfYFo2nyKDv42UcGcI+EvYlPAOXTsl3IHng42w9+jKy5m2BNusJ4JrJ4RrR3x7 G6yNAV2Ug4O0UmZIK0NCOHfUCjYkFnidfPAwqGn6oLp8cE3B1zFsKPp4zgc/5Xxwrrmv04Tj mR5dOR+cK0PAP0LK9SO6cj44OJnEcVyd7wiunBEuhCQCW763Rxcl7KCjlHmKQ+nT/iVj4GUm JIt4xi4b9gijmqaPKmSEG2UltVwOfSuPNlmkUEZ4QtHyc0746+SEO19/hGl0R90IH4EAEwpa +/sCpyG7RfTo2lPp+5diC7/cw6tPJWPESVxyZI8uupYENajMVINSbSWTVrsUR7mC9x/UoJmj cg42M5xbKYYOjc6i/JPICNfKF41Fhjx6dOW4jDXWUxkuLNOB6x5u+hKIBhkaj+DKR5v+rgK5 DQnYoqQcJJ8ypxUntZYZY32xK2lSck4osYVJOUg+c0bllxqtrQ82WZ3S2f5cWvYUs8EF7HCJ pUMPyrMga4TXJR0npCJySHP2dHXpwHVPNa1veoE7HO6wlU80/U0VUmwUwUWZO8grZYYQ0VDq hFMcHkaTVBTcHG6p9lLmDvLK9FG1oRnKpbBGKTbUFensTZ+zwAc9Myq8wkQi49j38MoOpM9r JFojZY8RXXsqNUf3Je3R1SfStw8zyLqF9/CirB7UmTJPxwh+qxI+KS+V/g6cJb6U1IM4M31Q rTvOrfTNmZl0KTGSc6+ed5cDDk+qPzpEurE9unKQxLQ6c3Rd8A5dl56t0oQ7ZHGsDlyZnK1y hGIDYj26KDUH2aXMkF0q7XwXNWcl+AxDxxsDKeCurHA+jGqaPqrQmVkrDc8wrDmJZ6Hs7HCf YAq4M7BxB7pDBksivHawhEmfjYwMlgRw1YmUVBigO9w6GMF1J1H60pQKW7i8Rxfl7yCvlDlC RK0l7KGA74DBTYIXqjXRhXNZgrwyfVRhw8AEZ1ZbzlP7Opw77rzNBHDFBGHYHLMeXdmHVozB dw5beiqA6y5lUvjmwhbbP65DV04Abxv6GGT99x5dlIODilLm9Xw0gjtfi9XQFL2KjwQUjm8E GWXmqCwzsLIYpYaSUzMTWwpTsByRgs+J388TQixskiSynW+Prpz4rS0jjiJVMD16BCMTEva4 0p58BTKqH9EjGJkSkYFttG+KgzYyoEtStQp6SZWnLGSWKW2kk8kNw8qGO8KopnmjYppJqTS3 3CTqJVkhd/kxBQPuIf9KM8zlg6TtPGmPvnSk3i7O7fV6NV/sFuvVbDnxH+Vst/3Zi/1nsptt Pje7yWa2+txMZvP5ptluP15+b9Yr8o/iQ/vvPyl6+fBay/VmsoUfm72/nMCnuvnx+DNvI3v3 z0F4AsJI73/bXuPj5S+UzpxoU/DRV2fYa9+0f9Kujbf85qbN8fef097Zuhr+PH764vbxB//o 2YmPTftkLdTlnudtN3v2vLVP1z5CuP+mzJub2Zflrn02J4f0EcPX4yNfT4x8PYm4nhv5euy5 0O8NG6gQ7u3hW3L29JYv9Lv/EO510Di82Gd/mXmE773fhO3dbLV6ND0PF6f+VfbQdd8sUJHo 6/XXZtPMJ6gJejPDv5ttZstl85oT8LKRXOWaV3iDyl68qVyNsAl4sREjJLS+3Ij//NJsfrzc kP0VGlMMgbePMB8vFxGuX/xs9Ez++jMymilHMynoNaWKNSiKL8yGqZreFFVvOV3vkH1Y20rZ ddYbH5JFaOKwZYZ69AjMniCR9SV9uUQGLyO46jRKZ4hkuDStDlt3CqXThGtkp7EIzjHxWTXO UIwzIxOLgQWacS2tVCndPhQj+kA+Kc72f+jax+acFZm2b6yy3BiT0D7WOWJqVwtKPBU6CrHZ S4Rk2K+M1YZojcyMj+AypihliM8WRx6zB3AZUwTzSehILo7gQqZQSyxFJkhE8Bic1ilxc/rK +QKfVCjGqUvpyiRhSRuF0jq5bQ6lKeeFNMIpm9JQyvladWdGe3X5LNohZJYRa5CFdXt0GWO0 bzmBlOB32DKGSGYJ5Ui9WQSXMsUQ7pAF1yN4DNYLKtYMESt4QdK3htA+KWhIy7DXk7Nj0V7Q qmbY7hy4cMIYyqijMkGsBbxna6uaXov3vr4p8Sl+a2ylz4JBlo+K6EJMCLtaJYa0G3u2wB5c yBkFp85IjpRNdeBSpjBCHVKlEMFjcGHQfmaoJKWDPS14xE46Nahn3ccnEvjkQGoKkguDxDNX tqqppuDB2gQX8FVq4L4qF76KZhOdC8gkERTbn6cDl9rXwgqP1O902EJbSW6JRgZBO2w5Q7hB 9iWK4DEYLUgmcxpVMqqMpMwKx7hI8O40O6hNQTJaEEZm2A7enVNcGaA1Y0VitcLausg3yWjF lY5ob45TQxTHHnREdClvjhM5pE575sy12EKbSa7bYDVuM9mBy5liWIIpHjwG8wWxYYbWUBkh DfWFTq1RKcWZfIA2T2v4lPmCpDDDdueckJIr8OeGT/+OpVrHqzBfFY0g3lHiRAtkUC6CS5ki iGXYPVcHLmMKp5yoIYHZs6JALbaUIYKwhPJELXgM7goivaymgJxxzoyv1zNUpmVoL8fZKNwV pHhZtgvBlZC+JnNK3U9vu6jGXeemK9gHI197ZxU8DQwpvYvgEUxMUN5ZReGuyEPKCK47i4JK whxycYngurMogDM5N7iYRQSPQbAsaOtYRi9CmCTLjXM0seiOPznIK7r8lGGD8dM847Wl3CjH YVs/1IxiwHpdTe5cqE0KOp/ynLT4OkmLVijC+FDA5ukHFdF1M+6Y5ZZYhWT+Hl17IhkR2AYp Hbj2NAqvoEb2p+3Ro3B/6IHIsnogathaa6qUVmpoZR2iz3GCosH6abr1YXNghQ/oCpaqn+a1 W2e9xWSfOumLCSWSI7hQyEBaIpA1glpoqdRFAZ4VsrNWBJcyRRLHkGfoETwKp4U2gSyjTaAW jDutmbXUKZ7g0GpfmWocTgvtANOtb4MGXDtnHPX1Lo41aPCGOe1oEhi5L9SrKNJhiOhyJMwp MlkvggudrwhBhEVSTgSXMkURhdXzRPAo7BfUKCxD0mEoeOdGaOpdO5OQCGjoWIk7wfppuvWe /aSzzvO3NUP1lYbYT53UQff7S2O02hFLkY2pe3RBYxTSF4zgUqYYTiRFlqjvwMVM0eBeoffh HXoURgxaFpbZf015UQjwihzq5JfZfw3LiEHOkm59u8f1iT8cdj0qJfOn3eOeij/4IiasktZj ne8MiWzqFsGldrnwtcR20ongUlmEyP5sPFGGnGAAURwrzevAo/BZUKmwDKmHZtTBjl9KYxxX CWEvzQ42ScDyWdCppFsfah4KR2H7YE2KxqZkzcP3xWdHlMrIHWFoiV5El9rhSvy2MoJLbSs1 YRyZOx3B5UzRyLY9HXYU9gu6FJYhTDG06y9gffHutP2tyKsE+4z9gjIl3fqW/QR1JuQzJqYz HYpNvg/2O7J0RkWcRbc2COBypnBsEYEILpVFKInWQ8qqZ1mEAVwuodENiTn25DMCdhT+CioU liflUM5QBx+RZikhLjeasC5YP82z3u9DgXqZ5M4lFOL258UHJNLnlMY3ldJoGVCMRB7bduDK KY3WJ1Iiw/cRXDmlkSnwSpCdBCK4ckoj0/6uSM1hBx6FZIPgheWpRowVznuKlKUcASOaoGBJ Nkhe0q1vj4CZoYZap3VKKYf2CLhaWkuhnMaEIpHnrMbXyWp0fnesKPIUIKIrp+P52yqGPV2P 6MoT6c9c0RkAEV17In3LTIPtSxbRoywAQTXEsqQ31OfPKAE7j8QgIx1HNRSMn+YZz4W0khub zv8nc+Rz7GmNTsO3dagH5tPiFQFbxhBNvdIBqVeO4EKnLRrcK2WR2YQduJQphjCBrV/Rgccg NR6EOjxD66KFVNIqA5+PUUkVLASR4+i4g/XTHOudg30B5czAfzCX1m3xUHW1M6sdU2Kj4JLA /gXpMUR0IRo2jGD7lXbYQictThA9qK97etTSgUuZwokdrIz1zJQAHoX7glCFZwhVjBAKPhug EHCMVMqxjyBinLBpsH6aY71zVmimrFCO2aE6UkNB31Phvq/vMq2RUyrBuUPXXOjQxYzRRCPp MIJLmcI44QqZct6jixljCNdIoWaPHoUTg9CFZ0lFKLhSyigmhEhtijpOYmOwfppnPZdWW6WV ljTRen7Am31fnHjUiY3OamItMoYVwYV2uowSZpCV0yK40PbSWC/vRW4vO3ApUwyR2CSsCB6F 2YKIhWeIWLSXmQvOrZZapfhLmh2sZo1ltiBiybHe157T1joD5oOzmuTtnUxXldpeXrG9riVa I9MKe3SpkCM8P1jvLoJLbTENcVhTIricKUrjlDwddhT2C4IVniFYMbytyCOkNnZQMrB3r8vH EqwE66c51vtqZ04pDv9SMeQXDJ29n0RRhuNKcfQ1+C2yynYElzKFE4UNkUVwoQ0h87WzkSUY IricKQJbUiyCR2GwIFHhWSIPAd4b8Bc30iaevx4qYoBlsCBRSbe+jdZp42vlWqGdSYzW1fbf nuUpZhHbwLXOOY+PHSylvaOC3Ot24LrZek4BAVict9NhK2c8SgNkicwbjeDKGY/S+uaxSFFg Bx6FcYMshucJS4BppdCM8aGPf1BYMtLZcJDF5FkvLNPcCU5NaiRTVKviOFIX7KQ22Oc+2Ohz 89NIvhSScUKxrRDu4XWzBrWhsBfFdoLt0VWnEnbZXiWFzGzv0XUn0qtsCHzdkDuRiB5lNQoi J54hE5KhsbRRjkk9VNFloHvYSPn3wfppuvXtWuoM7C199mVqCTZ+KkWIjj3/0teoJVxLZMWN iC4U2VA6qS+GLtkYg1kriEbnZ0V0MWMsAccVuZxF9Cj8FvRFPENfBMTAFeXCtE1p0hpkm5Hi G0FflG59e/JujLTWaGFTq+bWdrbfIr0dTSImg4+ZMIbukR3hhY7ntTZESmQmVI8uFFVVxhDH cFXVIriUKVYTQZEKmx49CgUGhQ1PFqlQorT2TSOs9jv3lIRM5YvCjUOBQWKTbn2osqvg6VLS Da2DJ19k9+u7zMdkwjifQIZsxnMPL0WKzsCqigw29uhCqUJUGXwJzh5dzBhFBPZz6tFj0KII Gh2RoXKRPqFRMMGUliqlwo+0RB04O0LSYrB+mmN9e3ZvHeVWGmkSrD+Zs/u3kZPZZpFT5Fen R5fa+0rjq+MiMwwiuhD7O1/P0mA78kR0KWM0XF4hHeIePQrDBSWOyNCyaKapD0447qhOaRmj Gbx3HIYLSpx0632JF8rBcxVMM5FWYBzee1Ke39vPzeRUKFiWkJWzI7qUn2d8uzxkMaIeXWrH 6SxhCptTFNGFjNHw1YJbII2J6FFYMGhvREaTGVinnFNCMKq5GpL5793+qoONCrAsGLQ36daH MpRcSl9oYqhB8rkK5fGkaErFCGdIP6FHFzMG9sMSXT68Q5eKcFrnO54gPaiILrfeEKlxbb4j eBQaC0IbkSVVASr1GUNauaS8ofEKpQXrp+nWe2cOttmiTX2yMinNlFWsJX6uRol9NF5QjVJq SbjD5T1GcN2sQit9UV6OzB7t0XXnkVkFvp4dKpn47Di2Q9edSV/+m7Ch6rPPbAzgUYg2aHpE lioGNsxWWqOo1GJg8RzKKR9H0xOsn6Zb7/1FJazfNTNHh7Rug225itSv4C8g2nOX7feVEqm5 Tx+0yJzye/gIrKVTHiUjjWdLZKpLD689mZIRge0GHtHVp1LDHkdhP/EePsoiEGRRIqdzDzC/ lYwrbqlM6kyrx5JFBeunedZzZZnTlnKlk0T5mvBT6dxz9GmRmjky6IA8dUI7cKlIAmPEIrVK EVzqJMaXFxoqSvjsICaAi5liidPIukg9ehRmC/IjkdGVR3PT9ljkwhpJUxIiOTEjubdBfpRu fZsNJB1lilkYRGrP7VMpRfQuMiI5fGGI4FjHoYcXImNlVdsQD5mj3qFLncPA5ZVAxid6dDFj tM+4xB4KdehRWDDIXkSG7MVQyawTjjOmnEzwkAwlcpzeZMH6abr1bTk5xaQSwlo7pDcaLCdX hAX3bfKP4Wj8/SVFam0YgW8R0uvo4SPs+0zSvs8oX58cu+0L6GJzpuBLYxl6zjp47TmDWxJt kIf99/BRuDRIbESWxEYLX/zNAifxlFRELcfKLw/WT/Osd0Ib7wtbJlJ6joP17qQK/h51IiUs 5l70y5FdziK60H5ZOE2EGdpdPd0wR3SpbaoRhBnsQVFElzLGSsI5NrIa0aMwXFDQiAwFjabC Selg52m4HqLnvRwBu86R9sxBQZNufXskpCnl3PeqGapzOngkdCrRwNpeYqldM1ecSKxI5R5e atcMZEI1MmGwRxfbqAKZWIcsIhHRpYxxhlisZKZHj8GDMkhmZE5bG+eMZxMLzpJLSePxDYLG kcwE66fp1rc8SJXkzqsgWaKaWh1Ih38fPHhcuZSKacIGkxieqVE6dDFjpHcYkR5dRBeLjfrd MtLX7dHFlhxNnBsKxj9fcQJ6FCYL0hiZ1ebFaV+8Qwun6JDuYCibciQmC9KYdOs9kzkv6WTa MTsUeB1iMlctK/ycTYl9NF6QTenzJcTgQ/DUw4royvmUxvhzR2x774iunE/pBCcW2Qcigitn UzohgH3QksgOPQrVBv2NzFOwgNtFjS+9mVKit5WwjKNCDNZP86ynyhljYQNtU1ohtkctR5e4 fu7w/d4yKp1Rmkg9JJB9Ht3r4CMwV1prauGIctjiYT289mSC324c9pyoh1efTGYJxTaqu4eP shAEBZPMUzAxqf0ZkeSwHqT53CMtBEHBlG59uxAwLTllyuqhAlCDC8GpFNw49pxKp3wDCIPL HozgMqZo6usUIKkmggsFIxlsyiXDBiMjupQxkhLF0Q09OvQo3BZEQzJDNKQFlZ7bHLeUp9RF 14LQA6fIWG4LoqF06z23aS0UuOnKsZTjLc9t+lROiN5FVqWgRhAz1MTzWUW1Dl2IjGE7SIRB ujE9uhDtOKYIU8iDsx5dyhjqsySRdX979CgcGDQzMkN1YjhQIBVeMCO4TjgdMpzIcRpbBOun OdY7cJONUv5oy1KW5p2aU/Hvvr7LnErfJZoRbpDBv3t4OXPgeRyUne0xJ8CLmSN8p3OsMS24 mCnSECGR0Y57+CjMGDQ3MkNz43zxDqG1s1KalBzDdvM4Tg2iYP403fx266s58wTJTFrxjpox 0GOgxqNOkXTGWd+xFNl1NqILHaj7Ji0KG8Pq0aX2nLCIC471tyK6mDHc1xPB2tKCRyG4IKeR GXIazaiVRlggODeoSB+oNEnHKU4UrJ/mWO+cNoYJ+L9USVXW4DnQp9JmobbLV2oDzIQiBhvh j+hiG2BHuEJ29O3Rpfac3BDrkBlOPbqYMV7OjjXFY0dhwCCCkRkyEsOZFt7Pk0yJoRP6gc3v oQJnWAYMIph067tTbiGcpjYlGep0HLzjyoy0igErIVPuenQpY7gkjCM3qz26WHyTEU2Rwpse XcwYTYzDHs1H9ChEFrQuMkPr4pz3s5XTSpgkcTE4Q2ocNV+wfppufVsfwoEXqrRxSbXbPJPJ 2g0Bzw3BU5+UFzQEl8aCl4BttBDRdRP8nFSaCD3Upu6ZkR16BCNTmrFSmBtsV9sIHsFEl2Ai o+BVOWTCaY8eg3lVUNeorJYuRisq/RaayqGamUMnEOPkpAfrp+nWtxV+mbbMgekirVEXA4cg lXnj1a/Xq/lit1ivZsuJH8xst/3Zi71Vu9nmc7ObbGarz81kNp9vmu324+VCkX8UH+Dvf1L0 8uF1luvNZAs/Nnt/OYExbX48HnFbef5+FsL4A7Pf/7a9xsfLXyidgfft2R19dYa99k37J+3a eMtvbto0Ubj61d7Zuhr+LH764vbxhx4fYE8G80nz/c5/XoDf+ht3T+IWfjmbb39vmt39Lz+t 5z/uf5qvr7/cwpBhbV3t4N/f/gtQSwcILlFom5AtAABfTgIAUEsBAhQAFAAACAAA+bsqUIVs OYouAAAALgAAAAgAAAAAAAAAAAAAAAAAAAAAAG1pbWV0eXBlUEsBAhQAFAAACAAA+bsqUBQH WWV5AwAAeQMAABgAAAAAAAAAAAAAAAAAVAAAAFRodW1ibmFpbHMvdGh1bWJuYWlsLnBuZ1BL AQIUABQACAgIAPm7KlARXdXQhgQAAFwoAAAMAAAAAAAAAAAAAAAAAAMEAABzZXR0aW5ncy54 bWxQSwECFAAUAAgICAD5uypQtPdo0gUBAACDAwAADAAAAAAAAAAAAAAAAADDCAAAbWFuaWZl c3QucmRmUEsBAhQAFAAACAAA+bsqUAAAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAAAgoAAENv bmZpZ3VyYXRpb25zMi9tZW51YmFyL1BLAQIUABQAAAgAAPm7KlAAAAAAAAAAAAAAAAAYAAAA AAAAAAAAAAAAADgKAABDb25maWd1cmF0aW9uczIvZmxvYXRlci9QSwECFAAUAAAIAAD5uypQ AAAAAAAAAAAAAAAAHAAAAAAAAAAAAAAAAABuCgAAQ29uZmlndXJhdGlvbnMyL2FjY2VsZXJh dG9yL1BLAQIUABQAAAgAAPm7KlAAAAAAAAAAAAAAAAAaAAAAAAAAAAAAAAAAAKgKAABDb25m aWd1cmF0aW9uczIvc3RhdHVzYmFyL1BLAQIUABQAAAgAAPm7KlAAAAAAAAAAAAAAAAAaAAAA AAAAAAAAAAAAAOAKAABDb25maWd1cmF0aW9uczIvdG9vbHBhbmVsL1BLAQIUABQAAAgAAPm7 KlAAAAAAAAAAAAAAAAAaAAAAAAAAAAAAAAAAABgLAABDb25maWd1cmF0aW9uczIvcG9wdXBt ZW51L1BLAQIUABQAAAgAAPm7KlAAAAAAAAAAAAAAAAAfAAAAAAAAAAAAAAAAAFALAABDb25m aWd1cmF0aW9uczIvaW1hZ2VzL0JpdG1hcHMvUEsBAhQAFAAACAAA+bsqUAAAAAAAAAAAAAAA ABwAAAAAAAAAAAAAAAAAjQsAAENvbmZpZ3VyYXRpb25zMi9wcm9ncmVzc2Jhci9QSwECFAAU AAAIAAD5uypQAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAADHCwAAQ29uZmlndXJhdGlvbnMy L3Rvb2xiYXIvUEsBAhQAFAAICAgA+bsqUCTK+rWZAQAASgMAAAgAAAAAAAAAAAAAAAAA/QsA AG1ldGEueG1sUEsBAhQAFAAICAgA+bsqUHXtYVDPBgAAdycAAAoAAAAAAAAAAAAAAAAAzA0A AHN0eWxlcy54bWxQSwECFAAUAAgICAD5uypQn3X6iTEBAAAsBAAAFQAAAAAAAAAAAAAAAADT FAAATUVUQS1JTkYvbWFuaWZlc3QueG1sUEsBAhQAFAAICAgA+bsqUC5RaJuQLQAAX04CAAsA AAAAAAAAAAAAAAAARxYAAGNvbnRlbnQueG1sUEsFBgAAAAARABEAZQQAABBEAAAAAA== --l2egltguwm3evkqb Content-Type: application/x-sh Content-Disposition: attachment; filename="pushdown.sh" Content-Transfer-Encoding: quoted-printable #!/bin/bash=0A=0ARESULTS=3D$1=0A=0Aecho '' > $RESULTS.csv=0Aecho '' > $RESU= LTS-explains.log=0A=0Adropdb test > /dev/null 2>&1=0Acreatedb test > /dev/n= ull 2>&1=0A=0Apsql test -c "create table fact (dim_a_id int, dim_b_id int, = f1 double precision, f2 double precision)" > /dev/null 2>&1=0Apsql test -c = "create table dim_a (id int primary key, val double precision)" > /dev/null= 2>&1=0Apsql test -c "create table dim_b (id int primary key, val double pr= ecision)" > /dev/null 2>&1=0A=0Afor d in 100 1000 10000; do=0A=0A for n in = 1000000 10000000; do=0A=0A psql test -c 'truncate dim_a' > /dev/null 2>&1;= =0A psql test -c 'truncate dim_b' > /dev/null 2>&1;=0A psql test -c 'trun= cate fact' > /dev/null 2>&1;=0A=0A psql test -c "insert into dim_a select = i, random() from generate_series(1,$d) s(i)" > /dev/null 2>&1=0A psql test= -c "insert into dim_b select i, random() from generate_series(1,$d) s(i)" = > /dev/null 2>&1=0A=0A psql test -c "insert into fact select 1 + mod((rand= om()*100000)::int,$d), 1 + mod((random()*100000)::int,$d), random(), random= () from generate_series(1,$n) s(i)" > /dev/null 2>&1=0A=0A psql test -c 'v= acuum analyze' > /dev/null 2>&1=0A=0A psql test -c 'checkpoint' > /dev/nul= l 2>&1=0A=0A for w in 0 4; do=0A=0A for p in off on; do=0A=0A for q i= n "select sum(f1) from fact f join dim_a d1 on (d1.id =3D dim_a_id)" \=0A = "select d1.id, sum(f1) from fact f join dim_a d1 on (d1.id =3D dim_a_id)= group by d1.id" \=0A "select d1.val, sum(f1) from fact f join dim_a d1= on (d1.id =3D dim_a_id) group by d1.val" \=0A "select sum(f1) from fac= t f join dim_a d1 on (d1.id =3D dim_a_id) join dim_b d2 on (d2.id =3D dim_b= _id)" \=0A "select d1.id, sum(f1) from fact f join dim_a d1 on (d1.id = =3D dim_a_id) join dim_b d2 on (d2.id =3D dim_b_id) group by d1.id" \=0A = "select d1.val, sum(f1) from fact f join dim_a d1 on (d1.id =3D dim_a_id)= join dim_b d2 on (d2.id =3D dim_b_id) group by d1.val" \=0A "select d1= =2Eid, d2.id, sum(f1) from fact f join dim_a d1 on (d1.id =3D dim_a_id) joi= n dim_b d2 on (d2.id =3D dim_b_id) group by d1.id, d2.id" \=0A "select = d1.val, d2.val, sum(f1) from fact f join dim_a d1 on (d1.id =3D dim_a_id) j= oin dim_b d2 on (d2.id =3D dim_b_id) group by d1.val, d2.val"; do=0A=0A = echo "=3D=3D=3D=3D=3D=3D d=3D$d n=3D$n w=3D$w p=3D$p q=3D'$q' =3D=3D=3D=3D= =3D" >> $RESULTS-explains.log 2>&1=0A=0A psql test >> $RESULTS-explains= =2Elog 2>&1 < timing.log 2>&1 <> $RESULTS.csv=0A=0A done=0A=0A done= =0A=0A done=0A=0A done=0A=0A done=0A=0Adone=0A --l2egltguwm3evkqb--