<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.2.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" hreflang="en" /><updated>2021-09-18T17:18:51-05:00</updated><id>/feed.xml</id><title type="html">XOR Media</title><subtitle>Traffic Engineering, Observability, Etc.</subtitle><author><name>Ross McFarland</name></author><entry><title type="html">Puzzle Solver</title><link href="/puzzle-solver/" rel="alternate" type="text/html" title="Puzzle Solver" /><published>2015-01-09T00:00:00-06:00</published><updated>2015-01-09T00:00:00-06:00</updated><id>/puzzle-solver</id><content type="html" xml:base="/puzzle-solver/">&lt;h1 id=&quot;backstory&quot;&gt;Backstory&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/puzzle-solver.jpg&quot; alt=&quot;Final Puzzle
Solution&quot; /&gt;&lt;/p&gt;

&lt;p&gt;My brother got me a pretty cool puzzle for Christmas which claims to
have “Over 300,000 wrong ways to assemble the pieces, but only One right
way!”. The only hint/instructions are that the final solution will be a
3x3 square with six points and six holes on the outside.&lt;/p&gt;

&lt;p&gt;Both my wife and I played around with solving it for a decent amount of
time each and together some, probably a total of a couple hours. We both
could get 8 of the nine pieces placed (multiple times) but could never
find a setup that would fit the final piece. In talking about the puzzle
we discussed the brute force approach to solving it, trying every piece
in every possible place and rotation, …&lt;/p&gt;

&lt;p&gt;I realized that it would be pretty cool to actual code up a solution. So
I took the piece and threw them all out in the same orientation on the
kitchen floor and took a picture of them. I then cut them up with gimp,
and used convert to generate the 90, 180, and 270 rotated version. After
that it was a bit of html and css, and a decent amount of hacking around
in js (thought it would be the best way to do it so that others could
see/watch.) I started off making things more complicated than they
needed to be trying to keep track of what’d be placed where. After that
wrong turn I backtracked and realized that it would be much cleaner and
simpler to just have the pieces know when they’ve been placed and try to
place them again and just ask if that’s possible.&lt;/p&gt;

&lt;p&gt;After that change and getting rid of the rest of the wrong-turn it
probably took about 30m, maybe an hour to finish things up and what you
see to the right is the result, and the live version is below. The
example is running at 256 tries a second (if you’re browser is up to
it.)&lt;/p&gt;

&lt;p&gt;I was fully expecting the solver to run for a couple hours trying all of
the possibilities, but by random chance I managed to lay out the pieces,
cut them up, and enter them in to the code in an order that gets to the
correct answer after only 3554 placements. So what could of been hours
takes less than a minute.&lt;/p&gt;

&lt;p&gt;It was thrown together as quickly and is in the style of a hack rather
than a good/clean solution, but I’m reasonably happy with it. Let me
know what you think.&lt;/p&gt;

&lt;style&gt;
.slot {
    width: 100px;
    height: 100px;
}
table {
    border: 1px solid gray;
}
table td {
    border: 1px solid gray;
}
&lt;/style&gt;

&lt;table&gt;
    &lt;tr&gt;
        &lt;td&gt;
            &lt;img id=&quot;0&quot; class=&quot;slot&quot; src=&quot;/assets/images/puzzle/blank.png&quot; /&gt;
        &lt;/td&gt;
        &lt;td&gt;
            &lt;img id=&quot;1&quot; class=&quot;slot&quot; src=&quot;/assets/images/puzzle//blank.png&quot; /&gt;
        &lt;/td&gt;
        &lt;td&gt;
            &lt;img id=&quot;2&quot; class=&quot;slot&quot; src=&quot;/assets/images/puzzle//blank.png&quot; /&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;
            &lt;img id=&quot;3&quot; class=&quot;slot&quot; src=&quot;/assets/images/puzzle//blank.png&quot; /&gt;
        &lt;/td&gt;
        &lt;td&gt;
            &lt;img id=&quot;4&quot; class=&quot;slot&quot; src=&quot;/assets/images/puzzle//blank.png&quot; /&gt;
        &lt;/td&gt;
        &lt;td&gt;
            &lt;img id=&quot;5&quot; class=&quot;slot&quot; src=&quot;/assets/images/puzzle//blank.png&quot; /&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;
            &lt;img id=&quot;6&quot; class=&quot;slot&quot; src=&quot;/assets/images/puzzle//blank.png&quot; /&gt;
        &lt;/td&gt;
        &lt;td&gt;
            &lt;img id=&quot;7&quot; class=&quot;slot&quot; src=&quot;/assets/images/puzzle//blank.png&quot; /&gt;
        &lt;/td&gt;
        &lt;td&gt;
            &lt;img id=&quot;8&quot; class=&quot;slot&quot; src=&quot;/assets/images/puzzle/blank.png&quot; /&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;
&lt;div&gt;
    Ticks: &lt;span id=&quot;ticks&quot;&gt;0&lt;/span&gt;
&lt;/div&gt;

&lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js&quot;&gt;&lt;/script&gt;

&lt;script&gt;
var Piece = function (num, left, top, right, bottom) {
    var rotation = 0;
    var src = ['/assets/images/puzzle/piece_' + num + '.jpg', 
               '/assets/images/puzzle/piece_' + num + '-a.jpg',
               '/assets/images/puzzle/piece_' + num + '-b.jpg', 
               '/assets/images/puzzle/piece_' + num + '-c.jpg'];
    var types = [
        [left, top, right, bottom],
        [bottom, left, top, right],
        [right, bottom, left, top],
        [top, right, bottom, left],
    ];
    var placed = false;

    return {
        set_rotation: function (rot) {
            rotation = rot;
        },
        reset: function () {
            rotation = 0;
        },
        left_type: function () {
            return types[rotation][0];
        },
        top_type: function () {
            return types[rotation][1];
        },
        right_works: function (type) {
            return (types[rotation][2] + type) === 0;
        },
        bottom_works: function (type) {
            return (types[rotation][3] + type) === 0;
        },
        place: function (element) {
            element.src = src[rotation];
            placed = true;
        },
        unplace: function (element) {
            if (element) {
                element.src = '/assets/images/puzzle/blank.png';
            }
            placed = false;
        },
        placed: function (element) {
            return placed;
        },
        to_string: function () {
            var type = types[rotation];
            return 'Piece (' + num + ', ' + rotation + ', ' +
                type[0] + ', ' +
                type[1] + ', ' +
                type[2] + ', ' +
                type[3] + ')';
        }
    };
};
Piece.HEART = 1;
Piece.DIAMOND = 2;
Piece.CLOVER = 3;
Piece.SPADE = 4;

var Board = function (elements) {
    var slots = [null, null, null, null, null, null, null, null, null];
    var elements = elements;

    return {
        has: function (slot, piece) {
            // object equality
            return slots[slot] == piece;
        },
        clear: function (slot) {
            if (slots[slot]) {
                slots[slot].unplace (elements[slot]);
            }
            var piece = slots[slot];
            slots[slot] = null;
            return piece;
        },
        place: function (slot, piece) {
            if (slots[slot]) {
                return false;
            }
            var fits = false;
            switch (slot) {
                case 0: {
                    fits = true;
                    break;
                }
                case 1: {
                    // make sure it works with it's left neighbor
                    fits = !slots[0] || slots[0].right_works (piece.left_type ())
                    break;
                }
                case 2: {
                    // make sure it works with it's left neighbor
                    fits = !slots[1] || slots[1].right_works (piece.left_type ())
                    break;
                }
                case 3: {
                    // make sure it works with it's upstairs neighbor
                    fits = !slots[0] || slots[0].bottom_works (piece.top_type ())
                    break;
                }
                case 4: {
                    // make sure it works with it's upstairs and left neighbors
                    fits = (!slots[1] || slots[1].bottom_works (piece.top_type ())) &amp;&amp;
                        (!slots[3] || slots[3].right_works (piece.left_type ()));
                    break;
                }
                case 5: {
                    // make sure it works with it's upstairs and left neighbors
                    fits = (!slots[2] || slots[2].bottom_works (piece.top_type ())) &amp;&amp;
                        (!slots[4] || slots[4].right_works (piece.left_type ()));
                    break;
                }
                case 6: {
                    // make sure it works with it's upstairs neighbor
                    fits = !slots[3] || slots[3].bottom_works (piece.top_type ())
                    break;
                }
                case 7: {
                    // make sure it works with it's upstairs and left neighbors
                    fits = (!slots[4] || slots[4].bottom_works (piece.top_type ())) &amp;&amp;
                        (!slots[6] || slots[6].right_works (piece.left_type ()));
                    break;
                }
                case 8: {
                    // make sure it works with it's upstairs and left neighbors
                    fits = (!slots[5] || slots[5].bottom_works (piece.top_type ())) &amp;&amp;
                        (!slots[7] || slots[7].right_works (piece.left_type ()));
                    break;
                }
            }
            if (fits) {
                slots[slot] = piece;
                piece.place (elements[slot]);
            }
            return fits;
        },
        to_string: function () {
            var piece_to_string = function (p) {
                return p ? p.to_string() : 'null';
            };
            return 'Board [\n' +
                '  [\n' +
                '    ' + piece_to_string(slots[0]) + ',\n' +
                '    ' + piece_to_string(slots[1]) + ',\n' +
                '    ' + piece_to_string(slots[2]) + ',\n' +
                '  ],\n' +
                '  [\n' +
                '    ' + piece_to_string(slots[3]) + ',\n' +
                '    ' + piece_to_string(slots[4]) + ',\n' +
                '    ' + piece_to_string(slots[5]) + ',\n' +
                '  ],\n' +
                '  [\n' +
                '    ' + piece_to_string(slots[6]) + ',\n' +
                '    ' + piece_to_string(slots[7]) + ',\n' +
                '    ' + piece_to_string(slots[8]) + ',\n' +
                '  ],\n' +
                ']';
        }
    };
};

var solved = false;

var Solver = function (board, pieces, slot) {

    var piece = 0;
    var rotation = 0;
    var next = null;

    return {
        tick: function () {
            if (next) {
                if (next.tick ()) {
                    return true;
                }
                next = null;
            }

            board.clear (slot);
            var current = pieces[piece];
            if (!current.placed ()) {
                current.set_rotation (rotation);
                if (board.place (slot, current)) {
                    if (slot == 8) {
                        solved = true;
                    } else {
                        next = new Solver (board, pieces, slot + 1);
                    }
                }
            }

            if (rotation == 3) {
                rotation = 0;
                if (piece == 8) {
                    return false;
                } else {
                    piece++;
                }
            } else {
                rotation++;
            }

            return true;
        }
    };
};

$(document).ready (function () {
    var pieces = [
        new Piece (0, Piece.HEART, Piece.DIAMOND, -Piece.CLOVER, -Piece.CLOVER),
        new Piece (1, Piece.HEART, Piece.DIAMOND, -Piece.DIAMOND, -Piece.HEART),
        new Piece (2, Piece.DIAMOND, Piece.CLOVER, -Piece.CLOVER, -Piece.DIAMOND),
        new Piece (3, Piece.CLOVER, Piece.HEART, -Piece.SPADE, -Piece.HEART),
        new Piece (4, Piece.HEART, Piece.SPADE, -Piece.SPADE, -Piece.CLOVER),
        new Piece (5, Piece.SPADE, Piece.SPADE, -Piece.HEART, -Piece.CLOVER),
        new Piece (6, Piece.SPADE, Piece.DIAMOND, -Piece.HEART, -Piece.DIAMOND),
        new Piece (7, Piece.SPADE, Piece.DIAMOND, -Piece.SPADE, -Piece.HEART),
        new Piece (8, Piece.CLOVER, Piece.HEART, -Piece.DIAMOND, -Piece.CLOVER)
    ];

    var slots = [];
    $('.slot').each (function (i, slot) {
        slots[i] = slot;
    });
    var board = new Board (slots);
    var solver = new Solver (board, pieces, 0);

    var interval;

    var ticksElement = $('#ticks');
    var ticks = 0;
    var iteration = function () {
        if (!solver.tick () || solved) {
            clearInterval (interval);
        }
        ticksElement.html (++ticks);
    };

    interval = setInterval (iteration, 1 / 256 * 1000);
});
&lt;/script&gt;

&lt;!-- # category: misc--&gt;
&lt;!-- # date: 2015-01-09--&gt;
&lt;!-- # slug: puzzle-solver--&gt;
&lt;!-- # tags: algorithms, coding, examples, javascript--&gt;</content><author><name>Ross McFarland</name></author><summary type="html">Backstory</summary></entry><entry><title type="html">String Truncate Middle With Ellipsis</title><link href="/string-truncate-middle-with-ellipsis/" rel="alternate" type="text/html" title="String Truncate Middle With Ellipsis" /><published>2014-09-21T00:00:00-05:00</published><updated>2014-09-21T00:00:00-05:00</updated><id>/string-truncate-middle-with-ellipsis</id><content type="html" xml:base="/string-truncate-middle-with-ellipsis/">&lt;p&gt;There are times when you need to middle truncate a string. In many cases
it’s for UX/human purposes, though in some situations it’s the best way
to generate unique string for a length-limited field. This is the case I
ran in to recently in trying to automate submission of IAP to both
Google Play and the App Store which require short unique names for each
SKU.&lt;/p&gt;

&lt;h1 id=&quot;the-setup&quot;&gt;The Setup&lt;/h1&gt;

&lt;p&gt;Consider the following titles, each of which is 39 characters long.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;Midsomer Murders - Series 1 - Episode 1
Midsomer Murders - Series 1 - Episode 2
Midsomer Murders - Series 1 - Episode 3
Midsomer Murders - Series 1 - Episode 4
Midsomer Murders - Series 1 - Episode 5
Midsomer Murders - Series 2 - Episode 1
Midsomer Murders - Series 2 - Episode 2
Midsomer Murders - Series 2 - Episode 3
Midsomer Murders - Series 2 - Episode 4
Midsomer Murders - Series 2 - Episode 5
Midsomer Murders - Series 3 - Episode 1
Midsomer Murders - Series 3 - Episode 2
Midsomer Murders - Series 3 - Episode 3
Midsomer Murders - Series 3 - Episode 4
Midsomer Murders - Series 3 - Episode 5
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Assume we had to fit these strings in to a field we had no control over
that requires them to be 32 characters or less and unique, or perhaps
we’re displaying them in a UI where there’s not enough room for the full
title. The naive approach would be to truncate them to 32 characters in
length and add ellipsis to make it clear that the title has been
truncated.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;Midsomer Murders - Series 1 -...
Midsomer Murders - Series 1 -...
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That doesn’t work particularly well as it results in duplicates across
each series. Taking a closer look at the format of the titles, which in
this case are consistent, we notice that there’s two points that will
uniquely identify an episode. The series number and the episode number.
So what if we truncate things in the middle rather than the end.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;Midsomer Murderi...1 - Episode 1
Midsomer Murders...1 - Episode 2
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The code to do this is fairly simple and looks something like the
following.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;truncate_middle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# string is already short-enough
&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# half of the size, minus the 3 .'s
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;n_2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# whatever's left
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;n_1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n_2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'{0}...{1}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n_1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n_2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This process isn’t perfect though as with a different set of titles it
may truncate out the series number as result in duplicates. For UI
purposes this may be acceptable (a best effort,) but for something that
requires uniqueness won’t quite be enough. In my particular situation
the items have hex UUID’s as unique identifiers so the simplest thing to
do was to append a few characters of it to the end of the title before
truncating. This for all practical purposes insures uniqueness. What
other solutions can you think of?&lt;/p&gt;

&lt;!-- # category: code--&gt;
&lt;!-- # date: 2014-09-21 12:54--&gt;
&lt;!-- # slug: string-truncate-middle-with-ellipsis--&gt;
&lt;!-- # tags: python, coding, examples, strings--&gt;</content><author><name>Ross McFarland</name></author><summary type="html">There are times when you need to middle truncate a string. In many cases it’s for UX/human purposes, though in some situations it’s the best way to generate unique string for a length-limited field. This is the case I ran in to recently in trying to automate submission of IAP to both Google Play and the App Store which require short unique names for each SKU.</summary></entry><entry><title type="html">Natural Sort Order with Zero Padding</title><link href="/natural-sort-order-with-zero-padding/" rel="alternate" type="text/html" title="Natural Sort Order with Zero Padding" /><published>2013-11-23T00:00:00-06:00</published><updated>2013-11-23T00:00:00-06:00</updated><id>/natural-sort-order-with-zero-padding</id><content type="html" xml:base="/natural-sort-order-with-zero-padding/">&lt;p&gt;Which of the following lists is sorted in the most “natural” fashion?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;A:
    Elementary Season 1 Episode 1
    Elementary Season 1 Episode 10
    Elementary Season 1 Episode 11
    Elementary Season 1 Episode 12
    Elementary Season 1 Episode 13
    Elementary Season 1 Episode 2
    Elementary Season 1 Episode 3
    Elementary Season 1 Episode 4
    Elementary Season 1 Episode 5
    Elementary Season 1 Episode 6
    Elementary Season 1 Episode 7
    Elementary Season 1 Episode 8
    Elementary Season 1 Episode 9
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;B:
    Elementary Season 1 Episode 1
    Elementary Season 1 Episode 2
    Elementary Season 1 Episode 3
    Elementary Season 1 Episode 4
    Elementary Season 1 Episode 5
    Elementary Season 1 Episode 6
    Elementary Season 1 Episode 7
    Elementary Season 1 Episode 8
    Elementary Season 1 Episode 9
    Elementary Season 1 Episode 10
    Elementary Season 1 Episode 11
    Elementary Season 1 Episode 12
    Elementary Season 1 Episode 13
&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&quot;the-problem&quot;&gt;The Problem&lt;/h1&gt;

&lt;p&gt;While the former is technically sorted, it’s ordering is mathematical,
only taking in to account the character values at each index in turn.
The latter which we’ll refer to as human ordering where higher level
logic is applied to realized that “10” comes after “9” and not “1.” Note
that we’re not talking about “The” or “A,” removal which is another
interesting topic, we’re just focusing on numbers in strings here.&lt;/p&gt;

&lt;p&gt;Back on track… The simple “trick” to get a mathematical sorting
algorithm to result in the natural sort order is to zero pad the numbers
in the strings before handing them off to sorting.&lt;/p&gt;

&lt;p&gt;We’ll start with an example of zero padded strings so you can see what
we’re after. If you run the following strings through a sorting
algorithm they’ll come out in the expected order.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;Elementary Season 0001 Episode 0001
Elementary Season 0001 Episode 0010
Elementary Season 0001 Episode 0002
Elementary Season 0001 Episode 0011
&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id=&quot;the-code&quot;&gt;The Code&lt;/h1&gt;

&lt;p&gt;I’ve looked at several ways to do this using python and after a bit of
somewhat scientific benchmarking landed on the use of SRE_Pattern.sub
as the best balance of performance and simplicity.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maxint&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;re&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# optional '-' to support negative numbers
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_num_re&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;re&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;compile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sa&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'-?\d+'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# number of chars in the largest possible int
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_maxint_digits&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;maxint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# format for zero padding positive integers
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_zero_pad_int_fmt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'{0:0'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_maxint_digits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'d}'&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# / is 0 - 1, so that negative numbers will come before positive
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_zero_pad_neg_int_fmt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'/{0:0'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_maxint_digits&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'d}'&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_zero_pad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# if n is negative, we'll use the negative format and flip the number using
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# maxint so that -2 comes before -1, ...
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_zero_pad_int_fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; \
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_zero_pad_neg_int_fmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maxint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;zero_pad_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_num_re&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_zero_pad&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To use &lt;em&gt;zero_pad_numbers&lt;/em&gt; to sort we just provide it as the key
function to &lt;em&gt;sort/sorted&lt;/em&gt;. This transforms each element for the purpose
of ordering them, but doesn’t modify the elements returned so they’re in
the preferred ordering, but remain in their original form.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;unordered&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'file12.txt'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'file3.txt'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'file1.txt'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ordered&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unordered&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zero_pad_numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# ordered
#    ['file1.txt', 'file3.txt', 'file12.txt']
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;what-about-databases&quot;&gt;What About Databases&lt;/h1&gt;

&lt;p&gt;It’s common to need to order things in this manner when they’re
retrieved from a database. In most situations it’s not reasonable to
pull all of data back in to the web server for sorting, nor is it
practical to try and do the zero padding in the database/query.&lt;/p&gt;

&lt;p&gt;The best route to take here is to add an extra column for sorting, i.e.
name_sorted. You can then hook in to the save method of your object and
compute the sorted version of name. This way you only incur the cost of
zero padding once rather than every time the data is retrieved.&lt;/p&gt;

&lt;!-- # category: code--&gt;
&lt;!-- # date: 2013-11-23 06:21--&gt;
&lt;!-- # slug: natural-sort-order-with-zero-padding--&gt;
&lt;!-- # tags: python, coding, examples, sorting--&gt;</content><author><name>Ross McFarland</name></author><summary type="html">Which of the following lists is sorted in the most “natural” fashion? A: Elementary Season 1 Episode 1 Elementary Season 1 Episode 10 Elementary Season 1 Episode 11 Elementary Season 1 Episode 12 Elementary Season 1 Episode 13 Elementary Season 1 Episode 2 Elementary Season 1 Episode 3 Elementary Season 1 Episode 4 Elementary Season 1 Episode 5 Elementary Season 1 Episode 6 Elementary Season 1 Episode 7 Elementary Season 1 Episode 8 Elementary Season 1 Episode 9</summary></entry><entry><title type="html">High Performance Web - Asynchronous HTTP</title><link href="/high-performance-web-asynchronous-http/" rel="alternate" type="text/html" title="High Performance Web - Asynchronous HTTP" /><published>2013-09-02T00:00:00-05:00</published><updated>2013-09-02T00:00:00-05:00</updated><id>/high-performance-web-asynchronous-http</id><content type="html" xml:base="/high-performance-web-asynchronous-http/">&lt;h1 id=&quot;async-what&quot;&gt;Async-What&lt;/h1&gt;

&lt;p&gt;The secret to building high performance sites which depend on external
web services is asynchronous HTTP. The trick to asynchronous HTTP (or
anything with the exception of UI) is to avoid &lt;a href=&quot;http://callbackhell.com/&quot;&gt;callback
hell&lt;/a&gt;. Enter &lt;a href=&quot;http://en.wikipedia.org/wiki/Futures_and_promises&quot;&gt;futures/promise
objects&lt;/a&gt;. When used
correctly they make doing substantial asynchronous IO, relatively
straightforward.&lt;/p&gt;

&lt;p&gt;It took me only a week or two of my tenure at Amazon to run across the
mechanisms that allow its home page to depend on dozens of external
(web) service calls without falling over and devolving in to utter
chaos. Simplified for explanation, the page generation consists of two
major phases. The first allows the components of the page to fire off
their individual requests for data. Then comes page rendering. During
this phase the pieces of the page are individually rendering, waiting if
necessary, though ideally each section’s data is ready and waiting when
it’s turn comes.&lt;/p&gt;

&lt;h1 id=&quot;reality-check&quot;&gt;Reality Check&lt;/h1&gt;

&lt;p&gt;I’ll let you in on a secret. You’re not building Amazon.com, neither in
complexity nor scale. If you get there you’ll have a whole team to build
the sorts of frameworks they have to make what they do possible. What
you can do is leverage a simplfied version of the same concept to
improve the performance and stability of your projects.&lt;/p&gt;

&lt;h1 id=&quot;requests-futures&quot;&gt;requests-futures&lt;/h1&gt;

&lt;p&gt;python &lt;a href=&quot;http://docs.python-requests.org/en/latest/&quot;&gt;requests&lt;/a&gt; is a well
done library and if you’re using python and need to make a HTTP request
it’s the way to go. If you using requests and would like to explore an
asynchronous model
&lt;a href=&quot;http://github.com/ross/requests-futures/&quot;&gt;requests-futures&lt;/a&gt; (note: I’m
the author) makes the process as straightforward as possible.&lt;/p&gt;

&lt;p&gt;The idea for requests-futures came to me while sitting in a talk at
&lt;a href=&quot;https://us.pycon.org/2013/&quot;&gt;PyCon 2013&lt;/a&gt; that covered
&lt;a href=&quot;http://docs.python.org/dev/library/concurrent.futures.html&quot;&gt;concurrent.futures&lt;/a&gt;.
I started on it then and there and within a few hours of hacking had
pushed it up to github as a public repo. Not a whole lot has changed
since that first push, a few bug fixes and documentation improvements.
It’s so simple thanks to concurrent.futures that it “just works.”&lt;/p&gt;

&lt;p&gt;It’s probably time for an example. We’ll take the following set of
serial requests and convert them to happen in parallel.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;requests&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Session&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# first requests starts and blocks until finished
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response_one&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'http://httpbin.org/get'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# second request starts once first is finished
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response_two&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'http://httpbin.org/get?foo=bar'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# both requests are complete
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'response one status: {0}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response_one&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response_one&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'response two status: {0}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response_two&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response_two&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To make the same two requests in parallel we’ll switch to a
FuturesSession and instead of the get call returning a response object
it’ll return a Futures object. The result method can be called on that
Futures object to retrieve the response. That’s it, the only noticeable
API difference is that a future object is returned in place of the
response.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;requests_futures.sessions&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FuturesSession&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FuturesSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# first request is started in the background
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;future_one&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'http://httpbin.org/get'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# second requests is started immediately as well
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;future_two&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'http://httpbin.org/get?foo=bar'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# wait for the first request to complete, if it hasn't already
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response_one&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;future_one&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'response one status: {0}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response_one&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response_one&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# wait for the second request to complete, if it hasn't already
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response_two&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;future_two&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'response two status: {0}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response_two&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status_code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response_two&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;applying-it-to-the-web&quot;&gt;Applying it to the Web&lt;/h1&gt;

&lt;p&gt;So that’s pretty simple, but how would we go about applying it in a
real-world context, preferably one involved in rendering a web page. The
following example will show how this can be applied in to a Django
request.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;simple_view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# NOTE: I often used middleware to install a persistent session on to
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# the request object, but that's be omitted here
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FuturesSession&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# these requests are being made to grab data that we'll pass in as
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# context to the template, since httpbin.org is over the internet, the
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# requests can take a non-trivial amount of time, good thing they're
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# both happening in parallel rather than one and then the other
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;future_one&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'http://httpbin.org/get'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;future_two&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'http://httpbin.org/get?foo=bar'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# we could have any number of requests happening here
&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;response_one&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;future_one&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;response_two&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;future_two&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'response_one'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response_one&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;'response_two'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response_two&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render_to_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'app/simple_view.html'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                              &lt;span class=&quot;n&quot;&gt;RequestContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;wrap-up&quot;&gt;Wrap-up&lt;/h1&gt;

&lt;p&gt;While simple to use, futures are powerful and the above examples just
scratch the surface. You can see a few more examples in my post from a
few months ago about
&lt;a href=&quot;%7Cfilename%7C../ops/keeping-track-with-graphite-and-statsd.rst&quot;&gt;statsd&lt;/a&gt;.
There’s a lot more that we could go in to on the subject including: how
to handle dependencies between requests, tracking
performance/request-blocking, and general tuning of complex request
flows. We’ll leave things here for now, but feel free to tell me what
you’d like to hear more about in the comments below.&lt;/p&gt;

&lt;!-- # category: code--&gt;
&lt;!-- # date: 2013-09-02 7:37--&gt;
&lt;!-- # slug: high-performance-web-asynchronous-http--&gt;
&lt;!-- # tags: coding, examples, io, http, networking, performance, python, requests-utures, web --&gt;</content><author><name>Ross McFarland</name></author><summary type="html">Async-What The secret to building high performance sites which depend on external web services is asynchronous HTTP. The trick to asynchronous HTTP (or anything with the exception of UI) is to avoid callback hell. Enter futures/promise objects. When used correctly they make doing substantial asynchronous IO, relatively straightforward.</summary></entry><entry><title type="html">What Google gets right, and where it fails</title><link href="/what-google-gets-right-and-where-it-fails/" rel="alternate" type="text/html" title="What Google gets right, and where it fails" /><published>2013-06-22T00:00:00-05:00</published><updated>2013-06-22T00:00:00-05:00</updated><id>/what-google-gets-right-and-where-it-fails</id><content type="html" xml:base="/what-google-gets-right-and-where-it-fails/">&lt;p&gt;In the past couple days there’s been
&lt;a href=&quot;http://gawker.com/5392947/googles-broken-hiring-process&quot;&gt;several&lt;/a&gt;
&lt;a href=&quot;http://techcrunch.com/2013/06/22/the-technical-interview-is-dead/&quot;&gt;articles&lt;/a&gt;
about how Google’s interview process has failed. The headlines are
overblown, inaccurate really, but to be expected giving the goal of
getting clicks. In reality Peter Norvig was talking about
&lt;a href=&quot;http://friendfeed.com/peternorvig/7a110005/google-broken-hiring-process-gawker?embed=1&quot;&gt;counterintuitive
findings&lt;/a&gt;.
They were surprised to find that some of their best employees were not
unanimously voted in. That makes a lot of sense given my personal
experience with the Google interview process and my opinions of what
matters in making software engineering hires.&lt;/p&gt;

&lt;p&gt;In the end it all comes down to enthusiasm. My personal stab in the dark
would put it’s weight at 75%. The rest is equally split between
intelligence and the “right” way of thinking. GPA doesn’t matter. What
school you attended doesn’t count for much. And yes brain teasers won’t
tell you anything useful, at least beyond being a crude measure of raw
intelligence. Google doesn’t ask brain teasers, nor does Amazon or any
other decent tech company. I’m sure there are people going off script at
both companies who do so, but it’s not coached in either place for good
reason.&lt;/p&gt;

&lt;p&gt;My personal experience with Google’s process is that it’s basically a
final exam for a mid-level algorithms course at Stanford. In my opinion
that’s where they’re going wrong, but not failing. Google hires really
smart people, but the most intelligent people aren’t necessarily the
best software engineers. And the best software engineers aren’t
necessarily the most intelligent (I like to think I illustrate that
axiom.)&lt;/p&gt;

&lt;p&gt;I believe the key to finding the best people is to make the interview
process as realistic as possible. By that I don’t necessarily mean
asking a question/solving a problem that comes from stuff you really
work on. Most of the time real problems are too intricate to fit nicely
in an interview slot, it’s just not possible to transfer all of the
relevant context. The next best thing is working through a simpler, in
scope, problem together. Together is the key here. You need to ask a
problem that the candidate won’t &lt;em&gt;know&lt;/em&gt; the answer to. Something where
she’ll make a couple false starts, need to ask a few questions, have a
few things right, and importantly get a couple things wrong.&lt;/p&gt;

&lt;p&gt;It’s easier said than done, but that sets the stage for what really
matters. Yes she has to be decently intelligent and good at solving
problems, but the key is… Is she’s having &lt;em&gt;fun&lt;/em&gt;? Are you enjoying
working &lt;em&gt;with&lt;/em&gt; her and helping to move things along? Is a &lt;em&gt;decent&lt;/em&gt; first
pass at a workable solution emerging? Are good questions being asked?
Would you dread coming to work everyday if this is what it involved,
because more often than not that’s what it will involve.&lt;/p&gt;

&lt;p&gt;Pure behavioral interviews will give you a half-decent read on the 75%
of things that is summed up as enthusiasm, but it won’t do much for the
other 25%. I’ve found, without fail, that the key is to get at both of
those things in one go via the right process.&lt;/p&gt;

&lt;!-- # category: people--&gt;
&lt;!-- # date: 2013-06-22 2:38--&gt;
&lt;!-- # slug: what-google-gets-right-and-where-it-fails--&gt;
&lt;!-- # tags: hiring, interviewing, opinion--&gt;</content><author><name>Ross McFarland</name></author><summary type="html">In the past couple days there’s been several articles about how Google’s interview process has failed. The headlines are overblown, inaccurate really, but to be expected giving the goal of getting clicks. In reality Peter Norvig was talking about counterintuitive findings. They were surprised to find that some of their best employees were not unanimously voted in. That makes a lot of sense given my personal experience with the Google interview process and my opinions of what matters in making software engineering hires.</summary></entry><entry><title type="html">High Performance Web - Reducing Database Round Trips</title><link href="/high-performance-web-reducing-database-round-trips/" rel="alternate" type="text/html" title="High Performance Web - Reducing Database Round Trips" /><published>2013-05-13T00:00:00-05:00</published><updated>2013-05-13T00:00:00-05:00</updated><id>/high-performance-web-reducing-database-round-trips</id><content type="html" xml:base="/high-performance-web-reducing-database-round-trips/">&lt;h1 id=&quot;background&quot;&gt;Background&lt;/h1&gt;

&lt;p&gt;There are two main sources of latency in the backend of web
applications: rendering (HTML templating or data serialization) and IO
(database or external service calls.) Today we’ll look at the latter and
more specifically focus getting rid of extraneous database round trips.
The fastest query possible is one that doesn’t happen.&lt;/p&gt;

&lt;p&gt;Before we get in to the details I’ll mention the importance of schema,
but won’t spend time on it here. No single factor will affect the
overall responsiveness of your application, and more specifically your
ability to tune it, than an effective data(base) schema. This is
something we’ll return to with detail in the future, but I bring it up
now as schema issues can often limit your options.&lt;/p&gt;

&lt;p&gt;I’ll also mention caching. In an optimal situation the things we’ll talk
about will help to reduce the amount of time required to serve a result
that can’t be cached or is a cache miss, but just as reducing the number
of database round trips by optimizing querying helps, avoiding them
altogether via caching is a big win.&lt;/p&gt;

&lt;p&gt;A final note, I’ll discuss this topic in the context of Python (Django,)
but it applies equally well in any language and ORM. I cut my teeth with
Java (Hibernate) and have worked with Perl (DBIx::Class,) Ruby (Rails,)
and several others since.&lt;/p&gt;

&lt;h1 id=&quot;the-n1-selects-problem&quot;&gt;The N+1 Selects Problem&lt;/h1&gt;

&lt;p&gt;The most common and egregious round-trip problem is the &lt;a href=&quot;http://stackoverflow.com/questions/97197/what-is-the-n1-selects-issue&quot;&gt;n+1
selects&lt;/a&gt;
problem. In it’s simplest form it involves an object with children, a
&lt;a href=&quot;http://en.wikipedia.org/wiki/Cardinality_\(data_modeling\)&quot;&gt;one-to-many&lt;/a&gt;
relationship. A minimal example follows.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;country&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ForeignKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Country&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;related_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'states'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ordering&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'name'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,)&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;City&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ForeignKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;related_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'cities'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Meta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ordering&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'name'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We have states which have zero or more cities and our use case is to
print out a nested list of states and their cities.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;Alaska
    Anchorage
    Fairbanks
    Willow
California
    Berkeley
    Monterey
    Palo Alto
    San Diego
    San Francisco
    Santa Cruz
Kentucky
    Albany
    Monticello
    Lexington
    Louisville
    Somerset
    Stamping Ground
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The code to accomplish this looks something like:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.shortcuts&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render_to_response&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.template.context&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RequestContext&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;locations.models&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;State&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;list_locations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'states'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render_to_response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'list_locations.html'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                              &lt;span class=&quot;n&quot;&gt;RequestContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
&lt;span class=&quot;nt&quot;&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we run the above code to generate an HTML page and look at the
database queries, using
&lt;a href=&quot;https://github.com/django-debug-toolbar/django-debug-toolbar&quot;&gt;django-debug-toolbar&lt;/a&gt;,
we’ll see a single query to list the states and then a query for each of
the states to retrieve the cities. With 3 states that’s not a huge deal,
but if it were all 50 we’d be looking at 1 query, the +1, to get the
states and 50, the n, to get all of the cities.&lt;/p&gt;

&lt;h1 id=&quot;2n1-no-thats-not-a-thing&quot;&gt;2N+1 (no that’s not a thing)&lt;/h1&gt;

&lt;p&gt;Before we fix the N+1 queries I want to add an additional piece of
information for each state, it’s country. This one will go in the other
direction on a one-to-many relationship. Each state will have exactly
one country.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-txt&quot;&gt;Alaska (United States)
...
&lt;/code&gt;&lt;/pre&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Country&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CharField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;country&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;models&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ForeignKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Country&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;related_name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'states'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
&lt;span class=&quot;nt&quot;&gt;&amp;lt;li&amp;gt;&lt;/span&gt; ()
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we take a look at the SQL tab of django-debug-toolbar we’ll see there
are now queries happening to pull in the country object for each state.
Also note that we’re retrieving the same country over and over, since
it’s shared by all of the states.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/query-round-trips-before.png&quot; alt=&quot;2N+1 queries, not
good&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we have a couple interesting problems to solve, conveniently one for
each of Django ORM’s primary solutions.&lt;/p&gt;

&lt;h1 id=&quot;select_related&quot;&gt;select_related&lt;/h1&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;states&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select_related&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'country'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-related&quot;&gt;select_related&lt;/a&gt;
works by joining in SQL between the primary object (state) and the other
object (country.) In this case that will get rid of the extra queries to
fetch the country objects for each state. So if a database round-trip
takes 20ms to transit the network, run, and return we’ll see a N * 20ms
speedup. For any reasonable size of N that’ll be noticeable.&lt;/p&gt;

&lt;p&gt;The new query to retrieve the state objects will look something like the
following.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&quot;locations_state&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;INNER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;JOIN&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&quot;locations_country&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ON&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;&quot;locations_state&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;&quot;country_id&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&quot;locations_country&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&quot;locations_state&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;&quot;name&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ASC&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The above query replaces the original state fetching query and rids us
of the secondary queries to retrieve the country objects. There is
however a potential downside to solving the problem this way, namely
we’re getting back the same country object repeatedly and thus having to
send it’s columns through the ORM code over and over and creating lots
of duplicate objects. We’ll come back to this in a moment.&lt;/p&gt;

&lt;p&gt;One last thing before we move on, in Django’s ORM select_related does
not work when there are multiple objects on the other end of an
association. We can make use of it to grab &lt;strong&gt;the&lt;/strong&gt; country for a state,
but if we were to add ‘cities’ to the select_related call, nothing
would happen. Other ORMs (Hibernate for example) don’t share this
limitation, but you must be very careful when making use of it in those
situations. In those cases the join will duplicate the primary object’s
data for each secondary object. That can quickly balloon out of control
and leave the ORM processing lots of data/rows.&lt;/p&gt;

&lt;p&gt;Given all of this, one of the best uses of select_related is when
you’re fetching a single object and want to pull back (a) related object
in a single shot. It’ll do so in a single round-trip to the database and
won’t end up duplicating too much data, any in the case of Django ORM’s
one-to-one only support.&lt;/p&gt;

&lt;h1 id=&quot;prefetch_related&quot;&gt;prefetch_related&lt;/h1&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;states&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prefetch_related&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'country'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;'cities'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In contrast
&lt;a href=&quot;https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related&quot;&gt;prefetch_related&lt;/a&gt;
works by collecting all of the ids for the related objects, fetches them
in a single batch, and then transparently attaches them to the objects.
The best part is that it can be used on one-to-many relationships, which
is what the state to cities relationship is in our example.&lt;/p&gt;

&lt;p&gt;The SQL will now look something like the following.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&quot;locations_state&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&quot;locations_state&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;&quot;name&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ASC&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&quot;locations_country&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&quot;locations_country&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;&quot;id&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&quot;locations_city&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&quot;locations_city&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;&quot;state_id&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;IN&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;&quot;locations_city&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;&quot;name&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ASC&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So we’ve gone from 2N+1 queries to 3. Getting rid of N is a big deal. 3
* 20ms is way less than (2 * 50 + 1) * 20ms or even (50 + 1) * 20ms
in the case of using select_related alone.&lt;/p&gt;

&lt;p&gt;The above example uses prefetch on both country and cities. As mentioned
in the previous section all of the states share a single country and
when using select_related that means we pulled back and processed its
data N times along side each state object. In contrast using
prefetch_related we’ll only pull back the country object once. This
however comes at the cost of an extra db round trip so it may be
preferable to use a combination, you’ll have to test in your specific
circumstances. However, in this case using both select_related and
prefetch_related takes us down to 2 * 20ms, it’ll &lt;strong&gt;probably&lt;/strong&gt; be
faster than 3 queries, but there are a lot of potential factors.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;states&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select_related&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'country'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; \
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prefetch_related&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'cities'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/query-round-trips-after.png&quot; alt=&quot;2 queries, pretty
good&quot; /&gt;&lt;/p&gt;

&lt;h1 id=&quot;how-deep&quot;&gt;How Deep&lt;/h1&gt;

&lt;p&gt;What about when you want to span multiple levels? Both select_related
and prefetch_related can traverse relationships using
double-underscores. When you make use of the ability the intermediate
objects will be included as well. This can be extremely powerful, but a
little hard to grok in more complex object models.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# only works when there's a single object at each step
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;city&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;City&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select_related&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'state__country'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 1 query, no further db queries
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'{0} - {1} - {2}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;city&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;city&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                               &lt;span class=&quot;n&quot;&gt;city&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;country&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# works for both single and multiple object relationships
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;countries&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Country&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prefetch_related&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'states__cities'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 3 queries, no further db queries
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;country&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;countries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;country&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;states&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;city&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cities&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'{0} - {1} - {2}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;city&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;city&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                           &lt;span class=&quot;n&quot;&gt;city&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;country&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;prefetch_related-on-raw-queries&quot;&gt;prefetch_related on raw queries&lt;/h1&gt;

&lt;p&gt;One final Django specific note. In last week’s post on &lt;a href=&quot;%7Cfilename%7Cefficiently-querying-for-nearby-things.rst&quot;&gt;efficiently
querying for nearby
things&lt;/a&gt; I
worked through a complicated SQL query to find the closest objects to a
given lat/lon point. The best way to go about doing this sort of query
with Django is to use a &lt;a href=&quot;https://docs.djangoproject.com/en/dev/topics/db/sql/&quot;&gt;raw sql
query&lt;/a&gt;. The issue
is that raw query sets don’t support prefetch_related, which is a
bummer. There is however a work-around, you can directly make use of
prefetch_related_objects, which Django uses under the hood to power
prefetch_related.&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;django.db.models.query&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prefetch_related_objects&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# prefetch_related_objects requires a list, it won't work on a QuerySet so
# we need to convert with list()
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cities&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;City&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'&amp;lt;sql-query-for-nearby-cities&amp;gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;prefetch_related_objects&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cities&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'state__country'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,))&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# 3 queries, no further db queries
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;city&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cities&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;'{0} - {1} - {2}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;city&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;city&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                   &lt;span class=&quot;n&quot;&gt;city&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;country&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s pretty cool.&lt;/p&gt;

&lt;!-- # category: code--&gt;
&lt;!-- # date: 2013-05-13 7:14--&gt;
&lt;!-- # slug: high-performance-web-reducing-database-round-trips--&gt;
&lt;!-- # tags: db, examples, performance, sql--&gt;</content><author><name>Ross McFarland</name></author><summary type="html">Background There are two main sources of latency in the backend of web applications: rendering (HTML templating or data serialization) and IO (database or external service calls.) Today we’ll look at the latter and more specifically focus getting rid of extraneous database round trips. The fastest query possible is one that doesn’t happen.</summary></entry><entry><title type="html">Efficiently Querying for Nearby Things</title><link href="/efficiently-querying-for-nearby-things/" rel="alternate" type="text/html" title="Efficiently Querying for Nearby Things" /><published>2013-05-06T00:00:00-05:00</published><updated>2013-05-06T00:00:00-05:00</updated><id>/efficiently-querying-for-nearby-things</id><content type="html" xml:base="/efficiently-querying-for-nearby-things/">&lt;p&gt;It’s a fairly common use case to have a latitude and longitude and want
to find the closest objects to a given point. While there are
heavyweight solutions: &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.0/en/spatial-extensions.html&quot;&gt;MySQL Spatial
Extensions&lt;/a&gt;,
&lt;a href=&quot;http://postgis.net/&quot;&gt;PostGIS&lt;/a&gt;, they can be more trouble than they’re
worth especially if you’re making use of an ORM.&lt;/p&gt;

&lt;h1 id=&quot;euclidean-distance-naive-flawed-but-simple&quot;&gt;Euclidean Distance (naive, flawed, but simple)&lt;/h1&gt;

&lt;p&gt;The most naive approach is to calculate the &lt;a href=&quot;http://en.wikipedia.org/wiki/Euclidean_distance&quot;&gt;Euclidean
distance&lt;/a&gt; between the
objects and point. It works OK so long as the distances are small and
you’re closer to the equator than you are to the poles. You will likely
recognize the math from high school geometry class, &lt;strong&gt;a^2 + b^2 = c^2&lt;/strong&gt;.
A solution in sql (MySQL) might look something like the following.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Restaurant&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;INTEGER&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AUTO_INCREMENT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;VARCHAR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;DOUBLE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;DOUBLE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;37&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;757001&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;122&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;420588&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
               &lt;span class=&quot;n&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; 
               &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;110574&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;61087757687&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt;
               &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Restaurant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ASC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’re computing the square root of the differences between the two
points squared. If it’s less than our search radius we let it through
and sort the passing Restaurants by their distance away from the search
point. Note the use of a sub-select. Depending on the level of
strictness you have MySQL running with (keep your eye out for an
upcoming post) you cannot use an aggregate in a where clause. WHERE &lt;a href=&quot;http://stackoverflow.com/questions/2905292/where-vs-having&quot;&gt;is
applied&lt;/a&gt;
before computing aggregates. Alternatively you could make use of HAVING,
but I have chosen this route. The other thing that needs explaining is
the number 110574.61087757687. It’s the distance in meters of a single
degree of latitude. You’ll see it used throughout as we’ll be working in
meters.&lt;/p&gt;

&lt;h1 id=&quot;performance-too-much-math&quot;&gt;Performance (too much math)&lt;/h1&gt;

&lt;p&gt;There are two problems here, the first one is an issue of performance.
As written the above query will run 2 subtractions, take two things to
the power of 2, and then do a square root on every single row in the
&lt;strong&gt;Restaurant&lt;/strong&gt; table. As soon as you have a city’s worth of rows that’s
going to be a performance problem and it’ll only get worse from there.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;----+-------------+------------+------+---------------+------+---------+------+-------+-----------------------------+&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;select_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;possible_keys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;key&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ref&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rows&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Extra&lt;/span&gt;                       &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;----+-------------+------------+------+---------------+------+---------+------+-------+-----------------------------+&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;PRIMARY&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;derived2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ALL&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;          &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;35906&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Using&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Using&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filesort&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DERIVED&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Restaurant&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ALL&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;          &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32160&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;                             &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;----+-------------+------------+------+---------------+------+---------+------+-------+-----------------------------+&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rows&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;08&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There’s a relatively easy solution. We need to consider fewer rows and
avoid doing as much computation as possible. The trick is to create a
bounding box and only consider rows that fall inside of it. Since we are
searching within a radius we know that anything that falls outside of a
box with a width of &lt;strong&gt;2 * radius&lt;/strong&gt; centered around our point will fall
outside of a circle of the same size.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;110574&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;61087757687&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lat_min&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lat_max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;110574&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;61087757687&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lon_min&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lon_max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
               &lt;span class=&quot;n&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; 
               &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;110574&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;61087757687&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt;
               &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Restaurant&lt;/span&gt; 
               &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BETWEEN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lat_min&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lat_max&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AND&lt;/span&gt;
                     &lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BETWEEN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lon_min&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lon_max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ASC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’ve added a where clause to the inner select that will filter out rows
that have no chance at being inside our radius so when our search point
is in San Francisco and we’re looking for stuff within 1000m we won’t
bother doing the math for things in NYC, or even on the other side of
town.&lt;/p&gt;

&lt;p&gt;That’s not quite enough though. If we use explain plan we’ll see that a
table scan is occurring to do the bounding box check. We’ll need an
index to address this.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;explain&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;----+-------------+------------+------+---------------+------+---------+------+-------+----------+-----------------------------+&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;select_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;possible_keys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;key&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ref&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rows&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filtered&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Extra&lt;/span&gt;                       &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;----+-------------+------------+------+---------------+------+---------+------+-------+----------+-----------------------------+&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;PRIMARY&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;derived2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ALL&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;          &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;122&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Using&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Using&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filesort&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DERIVED&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Restaurant&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ALL&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;          &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32160&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Using&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt;                 &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;----+-------------+------------+------+---------------+------+---------+------+-------+----------+-----------------------------+&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rows&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;warning&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;05&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INDEX&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Restaurant_lat_lon&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Restaurant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;explain&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;----+-------------+------------+-------+--------------------+--------------------+---------+------+------+----------+-----------------------------+&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;select_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;table&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;type&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;possible_keys&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;key&lt;/span&gt;                &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key_len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ref&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rows&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filtered&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Extra&lt;/span&gt;                       &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;----+-------------+------------+-------+--------------------+--------------------+---------+------+------+----------+-----------------------------+&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;PRIMARY&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;derived2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ALL&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;               &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;               &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;122&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Using&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Using&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filesort&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DERIVED&lt;/span&gt;     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Restaurant&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Restaurant_lat_lon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Restaurant_lat_lon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1043&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;   &lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;00&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;Using&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;where&lt;/span&gt;                 &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;----+-------------+------------+-------+--------------------+--------------------+---------+------+------+----------+-----------------------------+&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rows&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;warning&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;01&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Even in my tiny test dataset there’s over an order of magnitude
reduction in the number of &lt;strong&gt;rows&lt;/strong&gt; considered and it sped things up
around 5x (though admittedly both are fast and two runs is hardly a
scientific comparison.)&lt;/p&gt;

&lt;h1 id=&quot;correctness-now-thats-much-better&quot;&gt;Correctness (now that’s much better)&lt;/h1&gt;

&lt;p&gt;So now that things are fast and we’re avoiding doing math as much as
possible we can do a much better job at accurately computing the
distance between points. The Earth is not flat, it’s a sphere. While a
degree of latitude is constant anywhere it occurs, the same can’t be
said for longitude. A degree of longitude is much smaller near the poles
than the equator.&lt;/p&gt;

&lt;p&gt;Enter the &lt;a href=&quot;http://en.wikipedia.org/wiki/Haversine_formula&quot;&gt;Haversine
Formula&lt;/a&gt; which
accurately computes &lt;a href=&quot;http://en.wikipedia.org/wiki/Great-circle_distance&quot;&gt;great-circle
distances&lt;/a&gt;, the
distance between two points on a sphere, and while the Earth isn’t a
perfect sphere it’s much closer to one than a plane. I won’t bother
explaining the math, wikipedia already does so and I’d just mess it up.
I will however translate it in to SQL for you. We’ll also adjust our
bonding box calculation to account for longitudinal variation.&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;110574&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;61087757687&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lat_min&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lat_max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radians&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;110574&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;61087757687&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lon_min&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lon_max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12756200&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;
               &lt;span class=&quot;n&quot;&gt;asin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radians&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
                         &lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radians&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;
                         &lt;span class=&quot;n&quot;&gt;cos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radians&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;
                         &lt;span class=&quot;n&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radians&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;point_lon&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
               &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Restaurant&lt;/span&gt;
               &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lat&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BETWEEN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lat_min&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lat_max&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AND&lt;/span&gt;
                     &lt;span class=&quot;n&quot;&gt;lon&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BETWEEN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lon_min&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AND&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lon_max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;WHERE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;radius&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ORDER&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;BY&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;distance&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;ASC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you look closely you’ll notice a new magic number in there, 12756200
which is the diameter of the earth in meters. This query will perform
roughly the same as the previous performance enhanced version even
though it’s doing more complicated math. If we weren’t filtering with a
bounding box we’d see a much more apparent slow down.&lt;/p&gt;

&lt;p&gt;I plan to follow this post up next with with one on how I implemented
this solution with a Django model focusing on optimizing the queries run
to fetch related data. (&lt;a href=&quot;%7Cfilename%7Chigh-performance-web-reducing-database-round-trips.rst&quot;&gt;found
here&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Note: the foundation for my final solution was a MySQL presentation on
the subject, but I found it to be lacking in explanation and there were
quite a few things that could (needed to really) be optimized. If you’d
like to take a look at that document it can be found
&lt;a href=&quot;http://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;!-- # category: code--&gt;
&lt;!-- # date: 2013-05-06 7:44--&gt;
&lt;!-- # slug: efficiently-querying-for-nearby-things--&gt;
&lt;!-- # tags: algorithms, db, examples, geo, mysql, performance, sql--&gt;</content><author><name>Ross McFarland</name></author><summary type="html">It’s a fairly common use case to have a latitude and longitude and want to find the closest objects to a given point. While there are heavyweight solutions: MySQL Spatial Extensions, PostGIS, they can be more trouble than they’re worth especially if you’re making use of an ORM.</summary></entry><entry><title type="html">Keeping Track with Graphite and Statsd</title><link href="/keeping-track-with-graphite-and-statsd/" rel="alternate" type="text/html" title="Keeping Track with Graphite and Statsd" /><published>2013-04-11T00:00:00-05:00</published><updated>2013-04-11T00:00:00-05:00</updated><id>/keeping-track-with-graphite-and-statsd</id><content type="html" xml:base="/keeping-track-with-graphite-and-statsd/">&lt;p&gt;I recently gave a presentation on
&lt;a href=&quot;http://graphite.wikidot.com/&quot;&gt;graphite&lt;/a&gt; and
&lt;a href=&quot;https://github.com/etsy/statsd/&quot;&gt;statsd&lt;/a&gt; to the East Bay Django
&lt;a href=&quot;http://www.meetup.com/The-San-Francisco-Django-Meetup-Group/events/108289872/&quot;&gt;meetup&lt;/a&gt;
It’s more about the importance of stats in general when running
services, web or otherwise. The
&lt;a href=&quot;https://docs.google.com/presentation/d/1Qt_NtILScur1McU5vyRL68YKvzb6eNwdRqGtDOplhrU/edit?usp=sharing&quot;&gt;slides&lt;/a&gt;
are available and embedded here. There’s also a related &lt;a href=&quot;http://github.com/ross/statsd-demo.git&quot;&gt;demo
project&lt;/a&gt; that turned out to be
much more interesting than the slides themselves.&lt;/p&gt;

&lt;iframe src=&quot;https://docs.google.com/presentation/d/1Qt_NtILScur1McU5vyRL68YKvzb6eNwdRqGtDOplhrU/embed?start=false&amp;amp;loop=false&amp;amp;delayms=3000&quot; frameborder=&quot;0&quot; width=&quot;480&quot; height=&quot;389&quot; allowfullscreen=&quot;true&quot; mozallowfullscreen=&quot;true&quot; webkitallowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;

&lt;!-- # category: ops--&gt;
&lt;!-- # date: 2013-04-11 18:47--&gt;
&lt;!-- # slug: keeping-track-with-graphite-and-statsd--&gt;
&lt;!-- # tags: django, performance, python, stats--&gt;</content><author><name>Ross McFarland</name></author><summary type="html">I recently gave a presentation on graphite and statsd to the East Bay Django meetup It’s more about the importance of stats in general when running services, web or otherwise. The slides are available and embedded here. There’s also a related demo project that turned out to be much more interesting than the slides themselves.</summary></entry><entry><title type="html">Django ALLOWED_HOSTS and Amazon Elastic Load Balancer</title><link href="/django-allowed-hosts-and-amazon-elastic-load-balancer/" rel="alternate" type="text/html" title="Django ALLOWED_HOSTS and Amazon Elastic Load Balancer" /><published>2013-02-27T00:00:00-06:00</published><updated>2013-02-27T00:00:00-06:00</updated><id>/django-allowed-hosts-and-amazon-elastic-load-balancer</id><content type="html" xml:base="/django-allowed-hosts-and-amazon-elastic-load-balancer/">&lt;p&gt;A recent &lt;a href=&quot;https://www.djangoproject.com/weblog/2013/feb/19/security/&quot;&gt;Django security
release&lt;/a&gt;
added a new configuration option,
&lt;a href=&quot;https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts&quot;&gt;ALLOWED_HOSTS&lt;/a&gt;.
It’s optional in 1.3 and 1.4, but required in 1.5 setups. The relevant
detail is that when enabled in production Django will throw 500 errors
if the Host header doesn’t match one of the values in ALLOWED_HOSTS.&lt;/p&gt;

&lt;p&gt;The good news is that &lt;a href=&quot;http://aws.amazon.com/elasticloadbalancing/&quot;&gt;ELB&lt;/a&gt;
preserves the Host header on requests it forwards, as it would have to.
The bad news is that it doesn’t set a useful Host header during it’s
health and latency checks which causes them to fail and mark the host as
down. In fact, the two user different values.&lt;/p&gt;

&lt;p&gt;The health check uses the instance’s internal IP address which can be
determined and added to the ALLOWED_HOSTS list. The latency check on
the other hand uses another IP address that doesn’t belong to any
instances that I own. My guess would be that it’s the IP address of the
ELB node itself, but I have not had a chance to test/verify that.&lt;/p&gt;

&lt;p&gt;So by finding and adding the internal IP address to ALLOWED_HOSTS you
can make the health check happy and at least get your instances serving
requests, but the latency checks will still be 500’ing and there’s no
clean way to fix that.&lt;/p&gt;

&lt;p&gt;The health check problem coupled with the PITA of reliably getting the
internal IP address of a host lead me to look for a better solution.
What I ended up on involved munging the Host header if it looks like an
IP address. To do this I added the following my
&lt;a href=&quot;http://nginx.org/&quot;&gt;nginx&lt;/a&gt; site config.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$my_host&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# if the host header is an ip address change it to www.mysite.com&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# this works around requests coming from ELB with either the instance's&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# internal ip address in the case of health checks or an unknown internal&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# ip address in the case of latency checks. translating them to a known&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# good host header makes django's ALLOWED_HOSTS happy&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$host&lt;/span&gt; ~ &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\.\d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\.\d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\.\d&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;+&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$my_host&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;www.mysite.com&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

location @django &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    proxy_set_header Host &lt;span class=&quot;nv&quot;&gt;$my_host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The above initially sets $my_host to the $host header from ELB. It then
checks to see if it looks like a 4-segment IP address. If it does set
$my_host to the default “www.mysite.com.” Finally $my_host, whether
defaulted or overridden, is passed along to Django.&lt;/p&gt;

&lt;!-- # category: ops--&gt;
&lt;!-- # date: 2013-02-27 18:02--&gt;
&lt;!-- # slug: django-allowed-hosts-and-amazon-elastic-load-balancer--&gt;
&lt;!-- # tags: aws, django, elb, python--&gt;</content><author><name>Ross McFarland</name></author><summary type="html">A recent Django security release added a new configuration option, ALLOWED_HOSTS. It’s optional in 1.3 and 1.4, but required in 1.5 setups. The relevant detail is that when enabled in production Django will throw 500 errors if the Host header doesn’t match one of the values in ALLOWED_HOSTS.</summary></entry><entry><title type="html">Top 5 Percent</title><link href="/top-five-percent/" rel="alternate" type="text/html" title="Top 5 Percent" /><published>2013-02-11T00:00:00-06:00</published><updated>2013-02-11T00:00:00-06:00</updated><id>/top-five-percent</id><content type="html" xml:base="/top-five-percent/">&lt;p&gt;LinkedIn does a pretty good job of email communication. I probably read
50% of the emails they send me and I’ve remained subscribed to them for
quite a while now.&lt;/p&gt;

&lt;p&gt;A few minutes ago I received one of the best emails they’ve sent me yet,
subject:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Ross, congratulations! You have one of the top 5% most viewed
LinkedIn profiles for 2012!”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That’s pretty cool, no? I had to read that one. In the body of the
message they drop the number of users they have, 200M, and repeat the
5%. Doing the math that means that I have one of the top 10M profiles.
Heh, when put that way it doesn’t sound quite as good. It’s funny how
top 5% sounds better than top 10M. Both are good numbers to be a part
of, but 5% just sounds more exclusive.&lt;/p&gt;

&lt;p&gt;The email had a &lt;a href=&quot;http://www.linkedin.com/200million/?_ed=0_Gi90fGn_exGhy-F9eZImZUgwMhPWVoA3Bws6dRBpgOxhu5SxUMhIEhZ1_rgKSccdzlkGo8Flsl0FvwY6XoZyWeT8IOdyqIkBUdbO8nTNPAT8Bulbru0EgdnsFKPl3Vgz&quot;&gt;Read
More&lt;/a&gt;
link pointing to a page that was relatively well done page with a little
more detail and an
&lt;a href=&quot;http://blog.linkedin.com/wp-content/uploads/2013/02/200M_Milestone_Final.jpg&quot;&gt;infographic&lt;/a&gt;
that breaks down user numbers by country. There are 74M users in US, so
the top 5% there would come out to 3.7M. It feels better than 10M, but
is still a large number.&lt;/p&gt;

&lt;p&gt;All told this seems like a pretty good campaign for LinkedIn. It worked
on me since I’m talking about it in this post. What’s more is there’s a
pretty good chance that the 5% of most looked at profiles will include a
lot of people with large followings. I’d assume the Bay Area has a
disproportionate percentage of the top, at least in tech, given the
supply constrained nature of things here.&lt;/p&gt;

&lt;!-- # category: misc--&gt;
&lt;!-- # date: 2013-02-11 07:22--&gt;
&lt;!-- # slug: top-five-percent--&gt;
&lt;!-- # tags: resume, linkedin--&gt;</content><author><name>Ross McFarland</name></author><summary type="html">LinkedIn does a pretty good job of email communication. I probably read 50% of the emails they send me and I’ve remained subscribed to them for quite a while now.</summary></entry></feed>