• Sergey Petrunya's avatar
    Backport of: · 0e19f3e3
    Sergey Petrunya authored
    revno: 2876.47.174
    revision-id: jorgen.loland@oracle.com-20110519120355-qn7eprkad9jqwu5j
    parent: mayank.prasad@oracle.com-20110518143645-bdxv4udzrmqsjmhq
    committer: Jorgen Loland <jorgen.loland@oracle.com>
    branch nick: mysql-trunk-11765831
    timestamp: Thu 2011-05-19 14:03:55 +0200
    message:
      BUG#11765831: 'RANGE ACCESS' MAY INCORRECTLY FILTER 
                            AWAY QUALIFYING ROWS
            
      The problem was that the ranges created when OR'ing two 
      conditions could be incorrect. Without the bugfix, 
      "I <> 6 OR (I <> 8 AND J = 5)" would create these ranges:
      
      "NULL < I < 6",
      "6 <= I <= 6 AND 5 <= J <= 5",
      "6 < I < 8",
      "8 <= I <= 8 AND 5 <= J <= 5",
      "8 < I"
      
      While the correct ranges is
      "NULL < I < 6",
      "6 <= I <= 6 AND 5 <= J <= 5",
      "6 < I"
      
      The problem occurs when key_or() ORs
      (1) "NULL < I < 6, 6 <= I <= 6 AND 5 <= J <= 5, 6 < I" with 
      (2) "8 < I AND 5 <= J <= 5"
      
      The reason for the bug is that in key_or(), SEL_ARG *tmp is 
      used to point to the range in (1) above that is merged with 
      (2) while key1 points to the root of the red-black tree of 
      (1). When merging (1) and (2), tmp refers to the "6 < I" 
      part whereas the root is the "6 <= ... AND 5 <= J <= 5" part. 
      
      key_or() decides that the tmp range needs to be split into
      "6 < I < 8, 8 <= I <= 8, 8 < I", in which next_key_part of the 
      second range should be that of tmp. However, next_key_part is
      set to key1->next_key_part ("5 <= J <= 5") instead of 
      tmp->next_key_part (empty). Fixing this gives the correct but
      not optimal ranges:
      "NULL < I < 6",
      "6 <= I <= 6 AND 5 <= J <= 5",
      "6 < I < 8",
      "8 <= I <= 8",
      "8 < I"
      
      A second problem can be seen above: key_or() may create 
      adjacent ranges that could be replaced with a single range. 
      Fixes for this is also included in the patch so that the range
      above becomes correct AND optimal:
      "NULL < I < 6",
      "6 <= I <= 6 AND 5 <= J <= 5",
      "6 < I"
      
      Merging adjacent ranges like this gives a slightly lower cost 
      estimate for the range access.
    0e19f3e3
range_vs_index_merge_innodb.result 50.5 KB