2
  1. 查询花费了太多时间来执行,大约 130 分钟。
  2. 具有索引但查询未使用索引的表。
  3. 表大小约为 3000 万条记录。
  4. 请帮助我通过更改(或),(和)条件来重写查询。
  5. 该查询未在正常执行中使用,因此我们尝试使用强制索引但没有运气。

询问:

SELECT customer_history.customer_id,
        customer_history.row_mod,
        customer_history.row_create,
        customer_history.event_id,
        customer_history.event_type,
        customer_history.new_value,
        customer_history.old_value
FROM customer_history FORCE INDEX (customer_history_n2)
WHERE customer_id >= 1
        AND customer_id < 5000000
        AND (customer_history.row_mod >= '2012-10-01')
        OR (
                customer_history.row_create >= '2012-10-01'
                AND customer_history.row_create < '2012-10-13'
                );


Table structure

    CREATE TABLE `customer_history` (
      `customer_id` int(11) NOT NULL,
      `row_mod` datetime DEFAULT NULL,
      `row_create` datetime DEFAULT NULL,
      `event_id` int(11) DEFAULT NULL,
      `event_type` varchar(45) DEFAULT NULL,
      `new_value` varchar(255) DEFAULT NULL,
      `old_value` varchar(255) DEFAULT NULL,
      KEY `customer_id1` (`customer_id`),
      KEY `new_value_n1` (`new_value`),
      KEY `customer_history_n1` (`row_create`),
      KEY `customer_history_n2` (`row_mod`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8

解释计划:

+----+-------------+------------------+------+---------------------+------+---------+------+----------+-------------+
| id | select_type | table            | type | possible_keys       | key  | key_len | ref  | rows     | Extra       |
+----+-------------+------------------+------+---------------------+------+---------+------+----------+-------------+
|  1 | SIMPLE      | customer_history | ALL  | customer_history_n2 | NULL | NULL    | NULL | 18490530 | Using where |
+----+-------------+------------------+------+---------------------+------+---------+------+----------+-------------+
1 row in set (0
4

2 回答 2

1

您可以尝试将此查询分为两部分:

SELECT customer_history.customer_id,
        customer_history.row_mod,
        customer_history.row_create,
        customer_history.event_id,
        customer_history.event_type,
        customer_history.new_value,
        customer_history.old_value
FROM customer_history
WHERE customer_id >= 1
        AND customer_id < 5000000
        AND (customer_history.row_mod >= '2012-10-01')

SELECT customer_history.customer_id,
        customer_history.row_mod,
        customer_history.row_create,
        customer_history.event_id,
        customer_history.event_type,
        customer_history.new_value,
        customer_history.old_value
FROM customer_history
WHERE  customer_history.row_create >= '2012-10-01'
       AND customer_history.row_create < '2012-10-13';

并查看其中哪一个需要更长的时间来执行和优化它们。为了获得与第一个查询相同的结果集,您可以UNION在 MySQL 中使用这两个查询,或者简单地从应用程序层单独执行它们并在那里连接结果集。

于 2012-12-28T05:33:39.160 回答
1

啊,我想我知道你的问题是什么。根据MySQL 文档

通过指定 USE INDEX (index_list),您可以告诉 MySQL 仅使用一个命名索引来查找表中的行。替代语法 IGNORE INDEX (index_list) 可用于告诉 MySQL 不要使用某些特定的索引或索引。如果 EXPLAIN 显示 MySQL 正在使用可能索引列表中的错误索引,这些提示很有用。

您也可以使用 FORCE INDEX,它的作用类似于 USE INDEX (index_list),但另外假设表扫描非常昂贵。换句话说,仅当无法使用给定索引之一来查找表中的行时,才使用表扫描。

换句话说,通过使用 FORCE INDEX,您告诉 MySQL使用customer_history_n2索引并跳过所有其他可用索引。您需要从查询中删除 FORCE INDEX 子句,或者将其指定为 this 以便它将使用其他可用列的索引:

SELECT customer_history.customer_id,
    customer_history.row_mod,
    customer_history.row_create,
    customer_history.event_id,
    customer_history.event_type,
    customer_history.new_value,
    customer_history.old_value
FROM customer_history
    FORCE INDEX (customer_history_n2, customer_history_n1, customer_id1)
WHERE customer_id >= 1
    AND customer_id < 5000000
    AND (customer_history.row_mod >= '2012-10-01')
    OR (
        customer_history.row_create >= '2012-10-01'
        AND customer_history.row_create < '2012-10-13' );
于 2012-12-28T05:34:01.490 回答