MYSQL OR vs IN performance

后端 未结 14 1049
一向
一向 2020-11-22 04:12

I am wondering if there is any difference in regards to performance between the following

SELECT ... FROM ... WHERE someFIELD IN(1,2,3,4)

SELECT ... FROM ..         


        
14条回答
  •  眼角桃花
    2020-11-22 04:38

    Just when you thought it was safe...

    What is your value of eq_range_index_dive_limit? In particular, do you have more or fewer items in the IN clause?

    This will not include a Benchmark, but will peer into the inner workings a little. Let's use a tool to see what is going on -- Optimizer Trace.

    The query: SELECT * FROM canada WHERE id ...

    With an OR of 3 values, part of the trace looks like:

           "condition_processing": {
              "condition": "WHERE",
              "original_condition": "((`canada`.`id` = 296172) or (`canada`.`id` = 295093) or (`canada`.`id` = 293626))",
              "steps": [
                {
                  "transformation": "equality_propagation",
                  "resulting_condition": "(multiple equal(296172, `canada`.`id`) or multiple equal(295093, `canada`.`id`) or multiple equal(293626, `canada`.`id`))"
                },
    

    ...

                  "analyzing_range_alternatives": {
                    "range_scan_alternatives": [
                      {
                        "index": "id",
                        "ranges": [
                          "293626 <= id <= 293626",
                          "295093 <= id <= 295093",
                          "296172 <= id <= 296172"
                        ],
                        "index_dives_for_eq_ranges": true,
                        "chosen": true
    

    ...

            "refine_plan": [
              {
                "table": "`canada`",
                "pushed_index_condition": "((`canada`.`id` = 296172) or (`canada`.`id` = 295093) or (`canada`.`id` = 293626))",
                "table_condition_attached": null,
                "access_type": "range"
              }
            ]
    

    Note how ICP is being given ORs. This implies that OR is not turned into IN, and InnoDB will be performing a bunch of = tests through ICP. (I do not feel it is worth considering MyISAM.)

    (This is Percona's 5.6.22-71.0-log; id is a secondary index.)

    Now for IN() with a few values

    eq_range_index_dive_limit = 10; there are 8 values.

            "condition_processing": {
              "condition": "WHERE",
              "original_condition": "(`canada`.`id` in (296172,295093,293626,295573,297148,296127,295588,295810))",
              "steps": [
                {
                  "transformation": "equality_propagation",
                  "resulting_condition": "(`canada`.`id` in (296172,295093,293626,295573,297148,296127,295588,295810))"
                },
    

    ...

                  "analyzing_range_alternatives": {
                    "range_scan_alternatives": [
                      {
                        "index": "id",
                        "ranges": [
                          "293626 <= id <= 293626",
                          "295093 <= id <= 295093",
                          "295573 <= id <= 295573",
                          "295588 <= id <= 295588",
                          "295810 <= id <= 295810",
                          "296127 <= id <= 296127",
                          "296172 <= id <= 296172",
                          "297148 <= id <= 297148"
                        ],
                        "index_dives_for_eq_ranges": true,
                        "chosen": true
    

    ...

            "refine_plan": [
              {
                "table": "`canada`",
                "pushed_index_condition": "(`canada`.`id` in (296172,295093,293626,295573,297148,296127,295588,295810))",
                "table_condition_attached": null,
                "access_type": "range"
              }
            ]
    

    Note that the IN does not seem to be turned into OR.

    A side note: Notice that the constant values were sorted. This can be beneficial in two ways:

    • By jumping around less, there may be better caching, less I/O to get to all the values.
    • If two similar queries are coming from separate connections, and they are in transactions, there is a better chance of getting a delay instead of a deadlock due to overlapping lists.

    Finally, IN() with a lots of values

          {
            "condition_processing": {
              "condition": "WHERE",
              "original_condition": "(`canada`.`id` in (293831,292259,292881,293440,292558,295792,292293,292593,294337,295430,295034,297060,293811,295587,294651,295559,293213,295742,292605,296018,294529,296711,293919,294732,294689,295540,293000,296916,294433,297112,293815,292522,296816,293320,293232,295369,291894,293700,291839,293049,292738,294895,294473,294023,294173,293019,291976,294923,294797,296958,294075,293450,296952,297185,295351,295736,296312,294330,292717,294638,294713,297176,295896,295137,296573,292236,294966,296642,296073,295903,293057,294628,292639,293803,294470,295353,297196,291752,296118,296964,296185,295338,295956,296064,295039,297201,297136,295206,295986,292172,294803,294480,294706,296975,296604,294493,293181,292526,293354,292374,292344,293744,294165,295082,296203,291918,295211,294289,294877,293120,295387))",
              "steps": [
                {
                  "transformation": "equality_propagation",
                  "resulting_condition": "(`canada`.`id` in (293831,292259,292881,293440,292558,295792,292293,292593,294337,295430,295034,297060,293811,295587,294651,295559,293213,295742,292605,296018,294529,296711,293919,294732,294689,295540,293000,296916,294433,297112,293815,292522,296816,293320,293232,295369,291894,293700,291839,293049,292738,294895,294473,294023,294173,293019,291976,294923,294797,296958,294075,293450,296952,297185,295351,295736,296312,294330,292717,294638,294713,297176,295896,295137,296573,292236,294966,296642,296073,295903,293057,294628,292639,293803,294470,295353,297196,291752,296118,296964,296185,295338,295956,296064,295039,297201,297136,295206,295986,292172,294803,294480,294706,296975,296604,294493,293181,292526,293354,292374,292344,293744,294165,295082,296203,291918,295211,294289,294877,293120,295387))"
                },
    

    ...

                  "analyzing_range_alternatives": {
                    "range_scan_alternatives": [
                      {
                        "index": "id",
                        "ranges": [
                          "291752 <= id <= 291752",
                          "291839 <= id <= 291839",
                          ...
                          "297196 <= id <= 297196",
                          "297201 <= id <= 297201"
                        ],
                        "index_dives_for_eq_ranges": false,
                        "rows": 111,
                        "chosen": true
    

    ...

            "refine_plan": [
              {
                "table": "`canada`",
                "pushed_index_condition": "(`canada`.`id` in (293831,292259,292881,293440,292558,295792,292293,292593,294337,295430,295034,297060,293811,295587,294651,295559,293213,295742,292605,296018,294529,296711,293919,294732,294689,295540,293000,296916,294433,297112,293815,292522,296816,293320,293232,295369,291894,293700,291839,293049,292738,294895,294473,294023,294173,293019,291976,294923,294797,296958,294075,293450,296952,297185,295351,295736,296312,294330,292717,294638,294713,297176,295896,295137,296573,292236,294966,296642,296073,295903,293057,294628,292639,293803,294470,295353,297196,291752,296118,296964,296185,295338,295956,296064,295039,297201,297136,295206,295986,292172,294803,294480,294706,296975,296604,294493,293181,292526,293354,292374,292344,293744,294165,295082,296203,291918,295211,294289,294877,293120,295387))",
                "table_condition_attached": null,
                "access_type": "range"
              }
            ]
    

    Side note: I needed this due to the bulkiness of the trace:

    @@global.optimizer_trace_max_mem_size = 32222;
    

提交回复
热议问题