AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 204076
Accepted
dr_
dr_
Asked: 2018-04-17 05:58:10 +0800 CST2018-04-17 05:58:10 +0800 CST 2018-04-17 05:58:10 +0800 CST

为什么 pt-duplicate-key-checker 建议删除复合索引?

  • 772

pt-duplicate-key-checker这是搜索冗余索引的 Percona 工具的输出片段:

# Key myidx ends with a prefix of the clustered index
# Key definitions:
#   KEY `myidx` (`bar`,`foo`)
#   PRIMARY KEY (`foo`),
# Column types:
#         `bar` mediumint(8) unsigned not null default '0'
#         `foo` mediumint(8) unsigned not null auto_increment
# To shorten this duplicate clustered index, execute:
ALTER TABLE `mydb`.`mytable` DROP INDEX `myidx`, ADD INDEX `myidx` (`bar`);

为什么该工具会提示这个?原来的复合索引就不能用了吗?

据我了解,bar给定 PK 上的索引值得删除(bar,foo),但这里并非如此。

mysql index
  • 3 3 个回答
  • 405 Views

3 个回答

  • Voted
  1. Best Answer
    akuzminsky
    2018-04-17T20:43:31+08:002018-04-17T20:43:31+08:00

    主键是 InnoDB 中任何辅助键的一部分。

    • 2
  2. Rick James
    2018-05-01T20:19:25+08:002018-05-01T20:19:25+08:00

    我不同意该工具给出的分析。

    当我看到 时INDEX(bar, foo),我假设有一些查询需要这两列按此顺序位于此复合索引中。

    fooPK 与INDEX(bar)上述指标相同的事实无关紧要。

    当我看到 justINDEX(bar)时,我假设有一些查询(bar)不需要id.

    当我看到两者时,我会说较短的是“多余的”并建议将其删除。

    此外,“缩短这个重复的聚集索引”是错误的。 INDEX(bar)不比INDEX(bar, foo). 而且它不是“聚集索引”。只有PK是“聚集的”。

    如果是UNIQUE(bar, foo),那么我会建议更改UNIQUE为INDEX. 这样就INSERTs不必进行不必要的唯一性检查。

    • 2
  3. cEz
    2018-05-03T04:30:36+08:002018-05-03T04:30:36+08:00

    让我们创建一个简单的表,看看 MySQL(5.7.20 MySQL 社区服务器)必须告诉我们什么:

    mysql> create table test_dupe_key (foo int unsigned not null auto_increment primary key, bar int unsigned not null, random int unsigned not null default 0, key(bar, foo)) engine=InnoDB;
    Query OK, 0 rows affected (0.08 sec)
    
    mysql> show create table test_dupe_key\G
    *************************** 1. row ***************************
           Table: test_dupe_key
    Create Table: CREATE TABLE `test_dupe_key` (
      `foo` int(10) unsigned NOT NULL AUTO_INCREMENT,
      `bar` int(10) unsigned NOT NULL,
      `random` int(10) unsigned NOT NULL DEFAULT '0',
      PRIMARY KEY (`foo`),
      KEY `bar` (`bar`,`foo`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1
    1 row in set (0.00 sec)
    
    mysql> insert into test_dupe_key(bar) values (1), (2), (3);
    Query OK, 3 rows affected (0.00 sec)
    Records: 3  Duplicates: 0  Warnings: 0
    
    mysql> select * from test_dupe_key;
    +-----+-----+--------+
    | foo | bar | random |
    +-----+-----+--------+
    |   1 |   1 |      0 |
    |   2 |   2 |      0 |
    |   3 |   3 |      0 |
    +-----+-----+--------+
    3 rows in set (0.00 sec)
    

    这是一个可以从索引中读取的简单查询:

    mysql> explain format=json select foo, bar from test_dupe_key\G
    *************************** 1. row ***************************
    EXPLAIN: {
      "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "1.60"
        },
        "table": {
          "table_name": "test_dupe_key",
          "access_type": "index",
          "key": "bar",
          "used_key_parts": [
            "bar",
            "foo"
          ],
          "key_length": "8",
          "rows_examined_per_scan": 3,
          "rows_produced_per_join": 3,
          "filtered": "100.00",
          "using_index": true,
          "cost_info": {
            "read_cost": "1.00",
            "eval_cost": "0.60",
            "prefix_cost": "1.60",
            "data_read_per_join": "48"
          },
          "used_columns": [
            "foo",
            "bar"
          ]
        }
      }
    }
    1 row in set, 1 warning (0.00 sec)
    

    这表明密钥条已被使用并且有 2 个密钥部分,都被读取以产生长度为 8 (2x4) 的密钥。现在让我们切换单个字段的复合键并再次检查:

    mysql> alter table test_dupe_key drop key bar, add key(bar);
    Query OK, 0 rows affected (0.12 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    
    mysql> explain format=json select foo, bar from test_dupe_key\G
    *************************** 1. row ***************************
    EXPLAIN: {
      "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "1.60"
        },
        "table": {
          "table_name": "test_dupe_key",
          "access_type": "index",
          "key": "bar",
          "used_key_parts": [
            "bar"
          ],
          "key_length": "4",
          "rows_examined_per_scan": 3,
          "rows_produced_per_join": 3,
          "filtered": "100.00",
          "using_index": true,
          "cost_info": {
            "read_cost": "1.00",
            "eval_cost": "0.60",
            "prefix_cost": "1.60",
            "data_read_per_join": "48"
          },
          "used_columns": [
            "foo",
            "bar"
          ]
        }
      }
    }
    1 row in set, 1 warning (0.00 sec)
    

    现在只有关键部分和长度发生了变化,这是符合预期的,但它仍然是一个索引读取。如果我们将其转换为对 PK 字段的范围查询,并对索引字段进行约束,让我们看看会发生什么:

    mysql> explain format=json select foo, bar from test_dupe_key where bar = 1 and foo > 0\G
    *************************** 1. row ***************************
    EXPLAIN: {
      "query_block": {
        "select_id": 1,
        "cost_info": {
          "query_cost": "1.20"
        },
        "table": {
          "table_name": "test_dupe_key",
          "access_type": "range",
          "possible_keys": [
            "PRIMARY",
            "bar"
          ],
          "key": "bar",
          "used_key_parts": [
            "bar",
            "foo"
          ],
          "key_length": "8",
          "rows_examined_per_scan": 1,
          "rows_produced_per_join": 1,
          "filtered": "100.00",
          "using_index": true,
          "cost_info": {
            "read_cost": "1.00",
            "eval_cost": "0.20",
            "prefix_cost": "1.20",
            "data_read_per_join": "16"
          },
          "used_columns": [
            "foo",
            "bar"
          ],
          "attached_condition": "((`stack_204076`.`test_dupe_key`.`bar` = 1) and (`stack_204076`.`test_dupe_key`.`foo` > 0))"
        }
      }
    }
    1 row in set, 1 warning (0.00 sec)
    

    查询规划器已经考虑了查询的 PK,但选择了 的索引bar,它现在对之前读取的索引有一个有趣的变化,因为我们可以看到它现在再次显示为 2 个关键部分,长度为 8:

      "key": "bar",
      "used_key_parts": [
        "bar",
        "foo"
      ],
      "key_length": "8"
    

    这告诉我们MySQL已经访问了自动包含在二级索引中的PK

    • 2

相关问题

  • 是否有任何 MySQL 基准测试工具?[关闭]

  • 我在哪里可以找到mysql慢日志?

  • 如何优化大型数据库的 mysqldump?

  • 什么时候是使用 MariaDB 而不是 MySQL 的合适时机,为什么?

  • 组如何跟踪数据库架构更改?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve