title: Left Joins are what I want but they are very slow?
body: <p>Overview: </p>
  
  <p>I have three tables 1) subscribers, bios, and shirtsizes and i need to find the subscribers without a bio or shirtsizes </p>
  
  <p>the tables are laid out such as </p>
  
  <p><strong>subscribers</strong></p>
  
  <pre><code>| season_id |  user_id |
  </code></pre>
  
  <p><strong>bio</strong></p>
  
  <pre><code>| bio_id | user_id |
  </code></pre>
  
  <p><strong>shirt sizes</strong></p>
  
  <pre><code>| bio_id | shirtsize |
  </code></pre>
  
  <p>And I need to find all users who do not have a bio or shirtsize, (if no bio; then no shirtsize via relation) for any given season.</p>
  
  <p>I originally wrote a query like:</p>
  
  <pre><code>SELECT *
     FROM subscribers s 
     LEFT JOIN bio b ON b.user_id = subscribers.user_id 
     LEFT JOIN shirtsizes ON shirtsize.bio_id = bio.bio_id 
  WHERE s.season_id = 185181 AND (bio.bio_id IS NULL OR shirtsize.size IS NULL);
  </code></pre>
  
  <p>but it is taking 10 seconds to complete now. </p>
  
  <p>I am wondering how I can restructure the query (or possibly the problem) so that it will preform reasonably. </p>
  
  <p>Here is the mysql explain: (ogu = subscribers, b = bio, tn = shirtshize)</p>
  
  <pre><code>| id | select_type | table | type  | possible_keys | key     | key_len | ref         | rows   | Extra       |   
  +----+-------------+-------+-------+---------------+---------+---------+-------------+--------+-------------+    
  |  1 | SIMPLE      | ogu   | ref   | PRIMARY       | PRIMARY | 4       | const       |    133 | Using where |
  |  1 | SIMPLE      | b     | index | NULL          | PRIMARY | 8       | NULL        | 187644 | Using index |
  |  1 | SIMPLE      | tn    | ref   | nid           | nid     | 4       | waka2.b.nid |      1 | Using where | 
  </code></pre>
  
  <p>The above is pretty sanitized, here's the realz info:</p>
  
  <pre><code>mysql&gt; DESCRIBE subscribers
  +-----------+---------+------+-----+---------+-------+
  | Field     | Type    | Null | Key | Default | Extra |
  +-----------+---------+------+-----+---------+-------+
  | subscribers  | int(11) | NO   | PRI |         |       | 
  | uid       | int(11) | NO   | PRI |         |       | 
  
  
  mysql&gt; DESCRIBE bio;
  +-------+------------------+------+-----+---------+-------+
  | Field | Type             | Null | Key | Default | Extra |
  +-------+------------------+------+-----+---------+-------+
  | bio_id   | int(10) unsigned | NO   | PRI | 0       |       | 
  | uid   | int(10) unsigned | NO   | PRI | 0       |       | 
  
  
  mysql&gt; DESCRIBE shirtsize;
  +-------+------------------+------+-----+---------+-------+
  | Field | Type             | Null | Key | Default | Extra |
  +-------+------------------+------+-----+---------+-------+
  | bio_id   | int(10) unsigned | NO   | PRI | 0       |       | 
  | shirtsize   | int(10) unsigned | NO   | PRI | 0       |       | 
  </code></pre>
  
  <p>and the real query looks like:</p>
  
  <pre><code>SELECT ogu.nid, ogu.is_active, ogu.uid, b.nid AS bio_node, tn.nid AS size
                    FROM og_uid ogu
                    LEFT JOIN bio b ON b.uid = ogu.uid
                    LEFT JOIN term_node tn ON tn.nid = b.nid
                    WHERE ogu.nid = 185033 AND ogu.is_admin = 0
                    AND (b.nid IS NULL OR tn.tid IS NULL)
  </code></pre>
  
  <p>nid is season_id or bio_id (with a type); 
  term_node is going to be the shirtsize </p>