Skip to content

Slow query in the action to find forum errors #6920

@live627

Description

@live627

https://github.com/SimpleMachines/SMF2.1/blob/0f375f1b9b6682e9cf8415624296281b1559441e/Sources/RepairBoards.php#L603-L618

ANALYZE format=json SELECT
	t.id_topic, t.id_first_msg, t.id_last_msg,
	CASE WHEN MIN(ma.id_msg) > 0 THEN
		CASE WHEN MIN(mu.id_msg) > 0 THEN
			CASE WHEN MIN(mu.id_msg) < MIN(ma.id_msg) THEN MIN(mu.id_msg) ELSE MIN(ma.id_msg) END ELSE
		MIN(ma.id_msg) END ELSE
	MIN(mu.id_msg) END AS myid_first_msg,
	CASE WHEN MAX(ma.id_msg) > 0 THEN MAX(ma.id_msg) ELSE MIN(mu.id_msg) END AS myid_last_msg,
	t.approved, mf.approved, mf.approved AS firstmsg_approved
FROM smf_topics AS t
	LEFT JOIN smf_messages AS ma ON (ma.id_topic = t.id_topic AND ma.approved = 1)
	LEFT JOIN smf_messages AS mu ON (mu.id_topic = t.id_topic AND mu.approved = 0)
	LEFT JOIN smf_messages AS mf ON (mf.id_msg = t.id_first_msg)
WHERE t.id_topic BETWEEN 2 AND 3
GROUP BY t.id_topic, t.id_first_msg, t.id_last_msg, t.approved, mf.approved
ORDER BY t.id_topic

I had to tightly limit the range because otherwise it would timeout.

{
  "query_block": {
    "select_id": 1,
    "r_loops": 1,
    "r_total_time_ms": 8154.2,
    "filesort": {
      "sort_key": "t.id_topic, t.id_first_msg, t.id_last_msg, t.approved, mf.approved",
      "r_loops": 1,
      "r_total_time_ms": 0.0109,
      "r_used_priority_queue": false,
      "r_output_rows": 2,
      "r_buffer_size": "360",
      "temporary_table": {
        "table": {
          "table_name": "t",
          "access_type": "range",
          "possible_keys": ["PRIMARY"],
          "key": "PRIMARY",
          "key_length": "3",
          "used_key_parts": ["id_topic"],
          "r_loops": 1,
          "rows": 2,
          "r_rows": 2,
          "r_total_time_ms": 0.0099,
          "filtered": 100,
          "r_filtered": 100,
          "attached_condition": "t.id_topic between 2 and 3"
        },
        "block-nl-join": {
          "table": {
            "table_name": "ma",
            "access_type": "ALL",
            "r_loops": 1,
            "rows": 645486,
            "r_rows": 658956,
            "r_total_time_ms": 323.82,
            "filtered": 100,
            "r_filtered": 100
          },
          "buffer_type": "flat",
          "buffer_size": "256Kb",
          "join_type": "BNL",
          "attached_condition": "trigcond(ma.id_topic = t.id_topic and ma.approved = 1)",
          "r_filtered": 0.0072
        },
        "block-nl-join": {
          "table": {
            "table_name": "mu",
            "access_type": "ALL",
            "r_loops": 1,
            "rows": 645486,
            "r_rows": 658956,
            "r_total_time_ms": 325.84,
            "filtered": 100,
            "r_filtered": 100
          },
          "buffer_type": "incremental",
          "buffer_size": "256Kb",
          "join_type": "BNL",
          "attached_condition": "trigcond(mu.id_topic = t.id_topic and mu.approved = 0)",
          "r_filtered": 1.5e-4
        },
        "table": {
          "table_name": "mf",
          "access_type": "eq_ref",
          "possible_keys": ["PRIMARY", "id_member"],
          "key": "PRIMARY",
          "key_length": "4",
          "used_key_parts": ["id_msg"],
          "ref": ["smf21.t.id_first_msg"],
          "r_loops": 95,
          "rows": 1,
          "r_rows": 1,
          "r_total_time_ms": 0.0411,
          "filtered": 100,
          "r_filtered": 100
        }
      }
    }
  }
}

With new index on

ALTER TABLE smf_messages ADD INDEX idx_id_topic (id_topic, approved)

it becomes much faster

ANALYZE format=json SELECT
	t.id_topic, t.id_first_msg, t.id_last_msg,
	CASE WHEN MIN(ma.id_msg) > 0 THEN
		CASE WHEN MIN(mu.id_msg) > 0 THEN
			CASE WHEN MIN(mu.id_msg) < MIN(ma.id_msg) THEN MIN(mu.id_msg) ELSE MIN(ma.id_msg) END ELSE
		MIN(ma.id_msg) END ELSE
	MIN(mu.id_msg) END AS myid_first_msg,
	CASE WHEN MAX(ma.id_msg) > 0 THEN MAX(ma.id_msg) ELSE MIN(mu.id_msg) END AS myid_last_msg,
	t.approved, mf.approved, mf.approved AS firstmsg_approved
FROM smf_topics AS t
	LEFT JOIN smf_messages AS ma ON (ma.id_topic = t.id_topic AND ma.approved = 1)
	LEFT JOIN smf_messages AS mu ON (mu.id_topic = t.id_topic AND mu.approved = 0)
	LEFT JOIN smf_messages AS mf ON (mf.id_msg = t.id_first_msg)
WHERE t.id_topic BETWEEN 2 AND 3
GROUP BY t.id_topic, t.id_first_msg, t.id_last_msg, t.approved, mf.approved
ORDER BY t.id_topic
{
  "query_block": {
    "select_id": 1,
    "r_loops": 1,
    "r_total_time_ms": 0.4024,
    "filesort": {
      "sort_key": "t.id_topic, t.id_first_msg, t.id_last_msg, t.approved, mf.approved",
      "r_loops": 1,
      "r_total_time_ms": 0.0073,
      "r_used_priority_queue": false,
      "r_output_rows": 2,
      "r_buffer_size": "360",
      "temporary_table": {
        "table": {
          "table_name": "t",
          "access_type": "range",
          "possible_keys": ["PRIMARY"],
          "key": "PRIMARY",
          "key_length": "3",
          "used_key_parts": ["id_topic"],
          "r_loops": 1,
          "rows": 2,
          "r_rows": 2,
          "r_total_time_ms": 0.0105,
          "filtered": 100,
          "r_filtered": 100,
          "attached_condition": "t.id_topic between 2 and 3"
        },
        "table": {
          "table_name": "ma",
          "access_type": "ref",
          "possible_keys": ["id_topic"],
          "key": "id_topic",
          "key_length": "4",
          "used_key_parts": ["id_topic", "approved"],
          "ref": ["smf21.t.id_topic", "const"],
          "r_loops": 2,
          "rows": 5,
          "r_rows": 47.5,
          "r_total_time_ms": 0.0398,
          "filtered": 100,
          "r_filtered": 100,
          "using_index": true
        },
        "table": {
          "table_name": "mu",
          "access_type": "ref",
          "possible_keys": ["id_topic"],
          "key": "id_topic",
          "key_length": "4",
          "used_key_parts": ["id_topic", "approved"],
          "ref": ["smf21.t.id_topic", "const"],
          "r_loops": 95,
          "rows": 5,
          "r_rows": 0.4947,
          "r_total_time_ms": 0.1425,
          "filtered": 100,
          "r_filtered": 100,
          "using_index": true
        },
        "table": {
          "table_name": "mf",
          "access_type": "eq_ref",
          "possible_keys": ["PRIMARY", "id_member"],
          "key": "PRIMARY",
          "key_length": "4",
          "used_key_parts": ["id_msg"],
          "ref": ["smf21.t.id_first_msg"],
          "r_loops": 95,
          "rows": 1,
          "r_rows": 1,
          "r_total_time_ms": 0.009,
          "filtered": 100,
          "r_filtered": 100
        }
      }
    }
  }
}

The query coluld probably be rewritten but I want to save that for the future.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions