<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=utf-8"><meta name=Generator content="Microsoft Word 15 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
span.EmailStyle18
        {mso-style-type:personal-reply;
        font-family:"Calibri",sans-serif;
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-family:"Calibri",sans-serif;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]--></head><body lang=EN-US link=blue vlink=purple style='word-wrap:break-word'><div class=WordSection1><p class=MsoNormal>First of all is that really your join clause?  You seem to be missing an ON<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>from building b<o:p></o:p></p><p class=MsoNormal>join customer c<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>Also please output<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>EXPLAIN <o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>And the <o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><p class=MsoNormal>EXPLAIN ANALYZE of each query<o:p></o:p></p><p class=MsoNormal><o:p> </o:p></p><div style='border:none;border-left:solid blue 1.5pt;padding:0in 0in 0in 4.0pt'><div><div style='border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0in 0in 0in'><p class=MsoNormal><b>From:</b> postgis-users <postgis-users-bounces@lists.osgeo.org> <b>On Behalf Of </b>Cameron McCloud via postgis-users<br><b>Sent:</b> Wednesday, November 8, 2023 5:38 AM<br><b>To:</b> postgis-users@lists.osgeo.org<br><b>Cc:</b> Cameron McCloud <cameron.mccloud@gmail.com><br><b>Subject:</b> Re: [postgis-users] ST_DWithin slow if query is joined to another table, but fast if ST_DWithin cast to an integer<o:p></o:p></p></div></div><p class=MsoNormal><o:p> </o:p></p><div><p class=MsoNormal>Test code is here: <a href="https://github.com/cameronmccloud/postgis_slow_st_dwithin/blob/main/test.sql">https://github.com/cameronmccloud/postgis_slow_st_dwithin/blob/main/test.sql</a><o:p></o:p></p></div><p class=MsoNormal><o:p> </o:p></p><div><div><p class=MsoNormal>On Wed, Nov 8, 2023 at 9:25 AM Cameron McCloud <<a href="mailto:cameron.mccloud@gmail.com">cameron.mccloud@gmail.com</a>> wrote:<o:p></o:p></p></div><blockquote style='border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in'><div><p class=MsoNormal>Hi,<o:p></o:p></p><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>Postgis Version: 3.3.4<o:p></o:p></p></div><div><p class=MsoNormal>Postgres Version: 14.9<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>We have 2 tables, "building" with lat/long and "customer" with a FK to building. There's a 1:1 relationship between the two.<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>The test tables we're using have 16K rows each. Our production data has a lot more, but we could reproduce this on a smaller dataset.<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>We found some odd behaviour when using ST_DWITHIN in a WHERE clause but only when the "building" table is joined to the "customer" table.<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>We also found that converting the result of ST_DWITHIN to an integer (1/0 for true/false) and using the integer in the WHERE is fast.<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>-- This query works as expected and takes 60ms returning 6K rows.<o:p></o:p></p></div><div><p class=MsoNormal>select b.*<o:p></o:p></p></div><div><p class=MsoNormal>from building b<o:p></o:p></p></div><div><p class=MsoNormal>where<o:p></o:p></p></div><div><p class=MsoNormal>  st_dwithin(st_makepoint(b.longitude, b.latitude)::geography, st_makepoint(-96.7804060, 33.2471770)::geography, 50000);<o:p></o:p></p></div><div><p class=MsoNormal>         <o:p></o:p></p></div><div><p class=MsoNormal>-- This query is orders of magnitude slower - 3000ms, even though joining the two tables without the WHERE takes 30ms<o:p></o:p></p></div><div><p class=MsoNormal>select b.*<o:p></o:p></p></div><div><p class=MsoNormal>from building b<o:p></o:p></p></div><div><p class=MsoNormal>join customer c<o:p></o:p></p></div><div><div><p class=MsoNormal>where<o:p></o:p></p></div><div><p class=MsoNormal>  st_dwithin(st_makepoint(b.longitude, b.latitude)::geography, st_makepoint(-96.7804060, 33.2471770)::geography, 50000);<o:p></o:p></p></div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>-- This query converts the result of ST_DWITHIN to an integer. It's fast and takes 80ms<o:p></o:p></p></div><div><div><p class=MsoNormal>select b.*<o:p></o:p></p></div><div><p class=MsoNormal>from building b<o:p></o:p></p></div><div><p class=MsoNormal>join customer c<o:p></o:p></p></div><div><div><p class=MsoNormal>where<o:p></o:p></p></div><div><p class=MsoNormal>  case st_dwithin(st_makepoint(b.longitude, b.latitude)::geography, st_makepoint(-96.7804060, 33.2471770)::geography, 50000)<o:p></o:p></p></div></div><div><p class=MsoNormal>    when true then 1<o:p></o:p></p></div><div><p class=MsoNormal>    else 0<o:p></o:p></p></div><div><p class=MsoNormal>  end = 1;<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>We have no idea why this is the case, but we're curious. In our production scenario using the "case...when" brought a query down from 6 minutes to 6 seconds. We'd love to know why this might be and if there are other scenarios like this that could increase the performance of our Postgis queries.<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>Thanks,<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal>Cam.<o:p></o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><div><p class=MsoNormal><o:p> </o:p></p></div><p class=MsoNormal><o:p> </o:p></p></div></div></blockquote></div></div></div></body></html>