Оптимизация запроса с использованием индексов покрытия

У меня есть следующий запрос с подзапросом и самостоятельным соединением:

SELECT bucket.patient_sid AS sid
FROM 
(SELECT clinical_data.patient_sid, 
        clinical_data.lft, 
        clinical_data.rgt
FROM clinical_data INNER JOIN 
(SELECT clinical_data.patient_sid, 
        clinical_data.lft, 
        clinical_data.rgt, 
        clinical_data.attribute_id 
FROM clinical_data 
WHERE clinical_data.attribute_id = '33' AND clinical_data.string_value = '2160-0') AS attribute 
ON clinical_data.patient_sid = attribute.patient_sid 
    AND clinical_data.lft >= attribute.lft 
    AND clinical_data.rgt <= attribute.rgt 
WHERE clinical_data.attribute_id = '36') AS bucket;

У меня есть следующие индексы, определенные на этом:

KEY `idx_bucket` (`attribute_id`,`string_value`)
KEY `idx_self_join` (`patient_sid`,`attribute_id`,`lft`,`rgt`)

Когда я смотрю на запрос, используя EXPLAIN, подзапрос, использующий индекс покрытия idx_bucket, определенно оптимизирован, но само соединение и предложение where - нет. Кроме того, почему он сообщает, что только patient_sid а также attribute_id используются для used_key_parts в то время как attachment_condition показано для lft, rgt (что это значит?). И то и другое lft и 'rgt` просто определены как целые числа без специальных свойств, так почему они не используются в моем покрывающем индексе?

Еще более странно, когда я определяю

KEY `idx_self_join` (`patient_sid`,`lft`,`rgt`,`attribute_id`) 

только patient_sid зарегистрирован в used_key_parts. более того filtered падает до 1.60% от 11.00%!

{
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "645186.71"
    },
    "nested_loop": [
      {
        "table": {
          "table_name": "clinical_data",
          "access_type": "ref",
          "possible_keys": [
            "fk_attribute_idx",
            "idx_value_string",
            "idx_value_double",
            "idx_bucket",
            "idx_self_join_idx"
          ],
          "key": "idx_bucket",
          "used_key_parts": [
            "attribute_id",
            "string_value"
          ],
          "key_length": "308",
          "ref": [
            "const",
            "const"
          ],
          "rows_examined_per_scan": 126402,
          "rows_produced_per_join": 126402,
          "filtered": "100.00",
          "cost_info": {
            "read_cost": "126402.00",
            "eval_cost": "25280.40",
            "prefix_cost": "151682.40",
            "data_read_per_join": "46M"
          },
          "used_columns": [
            "patient_sid",
            "string_value",
            "attribute_id",
            "lft",
            "rgt"
          ],
          "attached_condition": "(`ns_large2`.`clinical_data`.`patient_sid` is not null)"
        }
      },
      {
        "table": {
          "table_name": "clinical_data",
          "access_type": "ref",
          "possible_keys": [
            "fk_attribute_idx",
            "idx_value_string",
            "idx_value_double",
            "idx_bucket",
            "idx_self_join_idx"
          ],
          "key": "idx_self_join_idx",
          "used_key_parts": [
            "attribute_id",
            "patient_sid"
          ],
          "key_length": "10",
          "ref": [
            "const",
            "ns_large2.clinical_data.patient_sid"
          ],
          "rows_examined_per_scan": 14,
          "rows_produced_per_join": 201169,
          "filtered": "11.11",
          "using_index": true,
          "cost_info": {
            "read_cost": "131327.39",
            "eval_cost": "40233.83",
            "prefix_cost": "645186.71",
            "data_read_per_join": "73M"
          },
          "used_columns": [
            "patient_sid",
            "attribute_id",
            "lft",
            "rgt"
          ],
          "attached_condition": "((`ns_large2`.`clinical_data`.`lft` >= `ns_large2`.`clinical_data`.`lft`) and (`ns_large2`.`clinical_data`.`rgt` <= `ns_large2`.`clinical_data`.`rgt`))"
        }
      }
    ]
  }
}

3 ответа

Решение

Вот ваш основной JOIN:

SELECT

FROM clinical_data cd1

JOIN clinical_data cd2
    ON cd1.patient_sid = cd2.patient_sid
    AND cd2.attribute_id = '33'

WHERE cd1.attribute_id = '36'

Вот что я наконец-то придумал:

SELECT
    cd1.patient_sid as sid

FROM clinical_data cd1

JOIN clinical_data cd2
    ON cd1.patient_sid = cd2.patient_sid
    AND cd1.lft >= cd2.lft 
    AND cd1.rgt <= cd2.rgt 

WHERE cd1.attribute_id = '36'
    AND cd2.attribute_id = '33'
    AND cd2.string_value = '2160-0'

"Used_columns" говорит, что это "покрытие". Окончательные "используемые ключевые части" не все используются в качестве "ключа", потому что они нужны в "диапазоне", а не в "=".

Избавьтесь от внешнего запроса:

        SELECT  clinical_data.patient_sid, clinical_data.lft, clinical_data.rgt
            FROM  clinical_data
            INNER JOIN  
              ( SELECT  clinical_data.patient_sid, clinical_data.lft, clinical_data.rgt,
                        clinical_data.attribute_id
                    FROM  clinical_data
                    WHERE  clinical_data.attribute_id = '33'
                      AND  clinical_data.string_value = '2160-0'
              ) AS attribute  ON clinical_data.patient_sid = attribute.patient_sid
              AND  clinical_data.lft >= attribute.lft
              AND  clinical_data.rgt <= attribute.rgt
            WHERE  clinical_data.attribute_id = '36'

Извините, но схема lft-rgt не очень эффективна.

Другие вопросы по тегам