【问题标题】:How do I add indexes to MySQL tables?如何为 MySQL 表添加索引?
【发布时间】:2011-03-01 11:08:13
【问题描述】:

我有一个非常大的 MySQL 表,其中包含大约 150,000 行数据。目前,当我尝试运行时

SELECT * FROM table WHERE id = '1';

代码运行良好,因为 ID 字段是主索引。 但是,对于该项目的最新发展,我必须按另一个字段搜索数据库。例如:

SELECT * FROM table WHERE product_id = '1';

该字段以前没有被索引;但是,我添加了一个,所以 mysql 现在索引该字段,但是当我尝试运行上述查询时,它运行得非常慢。 EXPLAIN 查询显示,当我已经添加了 product_id 字段时,没有索引,因此查询需要 20 分钟到 30 分钟的任何时间才能返回一行。

我的完整 EXPLAIN 结果是:

| id | select_type | table | type | possible_keys| key  | key_len | ref  | rows  | Extra       |
+----+-------------+-------+------+--------------+------+---------+------+-------+------------------+
|  1 | SIMPLE      | table | ALL  | NULL         | NULL | NULL    | NULL |157211 | Using where |
+----+-------------+-------+------+--------------+------+---------+------+-------+------------------+

请注意,我刚刚查看了一下,ID 字段存储为 INT,而 PRODUCT_ID 字段存储为 VARCHAR,这可能会有所帮助。这可能是问题的根源吗?

【问题讨论】:

  • 您能发布完整的EXPLAIN 结果吗?你确定没有没有索引吗?还是索引在那里,但 MySQL 选择不使用它?
  • 一个大表将有 150,000,000 条记录。一个非常大的表有 15,000,000,000 条记录。一个平均大小的表有 150,000 个。供将来参考。
  • 请注意,'OR' 可以使 MySql 不使用索引。我有 3 个 OR 的查询。每个都匹配一个索引,并在 15 毫秒内运行,总共花费了 25 秒到超时。所以我做了 3 个查询并将它们联合起来,500.000 行也花了 15 毫秒。
  • 考虑您存储的数据类型。性能可能会根据您比较的数据类型而变化。正如您所说的 PRODUCT_ID 是 VARCHAR 数据类型,请尝试将其更改为 INT 并索引该列。

标签: mysql optimization indexing row


【解决方案1】:

使用phpmyadmin,MySQL 管理的好工具,包括索引

【讨论】:

  • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
【解决方案2】:

您可以使用此语法添加索引并控制索引的类型(HASH 或 BTREE)。

create index your_index_name on your_table_name(your_column_name) using HASH;

create index your_index_name on your_table_name(your_column_name) using BTREE;

您可以在此处了解 BTREE 和 HASH 索引之间的区别: http://dev.mysql.com/doc/refman/5.5/en/index-btree-hash.html

【讨论】:

  • 当我看到使用显示索引时,哈希转换为 btree。
  • 如果我没有指定,Hash 和 BTree 的默认值是什么?
  • @RNKushwaha 因为 InnoDB 和 MyIsam 不支持 HASH、AFAIK,只有内存和 NDB 存储引擎支持它
【解决方案3】:

更好的选择是在 CREATE TABLE 查询期间直接添加约束(假设您有关于表的信息)

CREATE TABLE products(
    productId INT AUTO_INCREMENT PRIMARY KEY,
    productName varchar(100) not null,
    categoryId INT NOT NULL,
    CONSTRAINT fk_category
    FOREIGN KEY (categoryId) 
    REFERENCES categories(categoryId)
        ON UPDATE CASCADE
        ON DELETE CASCADE
) ENGINE=INNODB;

【讨论】:

    【解决方案4】:
    ALTER TABLE `table` ADD INDEX `product_id_index` (`product_id`)
    

    永远不要在 MySQL 中将 integerstrings 进行比较。如果idint,请去掉引号。

    【讨论】:

    • 使用SHOW INDEXES FROM YOURTABLEdev.mysql.com/doc/refman/5.0/en/show-index.html检查索引是否已经添加
    • 今天我遇到了@Michael 描述的确切问题,解决方案是“永远不要将整数与 mysql 中的字符串进行比较”。谢谢。
    • @zerkms Never compare integer to strings in mysql 为什么不呢?在这种情况下它不会自动将字符串转换为数字吗?
    • @x-yuri 我曾亲眼目睹过投错操作数导致全扫描的案例。并不是说没有意义。
    • 好吧,type conversion rules 说这不应该发生。但我不会为此担保。至于“没有意义”,当然,如果你自己写声明。但是在生成时才有意义。如果可以将其转换为字符串并让mysql 处理它,为什么还要费心适应传递的变量的类型...
    【解决方案5】:

    可以添加两种类型的索引:定义主键时,MySQL默认将其作为索引。

    说明

    主键作为索引

    假设您有一个tbl_student 表并且您希望student_id 作为主键:

    ALTER TABLE `tbl_student` ADD PRIMARY KEY (`student_id`)
    

    上面的语句添加了一个主键,表示索引值必须唯一,不能为NULL。

    指定索引名称

    ALTER TABLE `tbl_student` ADD INDEX student_index (`student_id`)
    

    以上语句将创建一个带有student_index 名称的普通索引。

    创建唯一索引

    ALTER TABLE `tbl_student` ADD UNIQUE student_unique_index (`student_id`)
    

    这里,student_unique_index 是分配给 student_id 的索引名称,并创建一个值必须唯一的索引(这里可以接受 null)。

    全文选项

    ALTER TABLE `tbl_student` ADD FULLTEXT student_fulltext_index (`student_id`)
    

    上面的语句将使用student_fulltext_index创建全文索引名称,您需要MyISAM Mysql Engine。

    如何删除索引?

    DROP INDEX `student_index` ON `tbl_student`
    

    如何查看可用索引?

    SHOW INDEX FROM `tbl_student`
    

    【讨论】:

      【解决方案6】:

      值得注意的是,多个字段索引可以显着提高您的查询性能。所以在上面的例子中,我们假设 ProductID 是唯一要查找的字段,但是如果查询说 ProductID = 1 AND Category = 7 那么多列索引会有所帮助。这是通过以下方式实现的:

      ALTER TABLE `table` ADD INDEX `index_name` (`col1`,`col2`)
      

      此外,索引应与查询字段的顺序相匹配。在我的扩展示例中,索引应该是 (ProductID,Category) 而不是相反。

      【讨论】:

      • 很好,明确命名索引可以轻松逆转。
      • 能否引用the index should match the order of the query fields的出处?
      【解决方案7】:

      你说你有一个索引,解释说不然。但是,如果你真的这样做了,这就是如何继续:

      如果你在列上有索引,而 MySQL 决定不使用它,可能是因为:

      1. 查询中还有一个 MySQL 认为更适合使用的索引,它只能使用一个。如果通常的检索方法是按多于一列的值,则解决方案通常是跨多列的索引。
      2. MySQL 确定有很多匹配行,并认为 tablescan 可能更快。如果不是这样,有时ANALYZE TABLE 会有所帮助。
      3. 在更复杂的查询中,它决定不使用它基于查询计划中极其聪明的深思熟虑的巫术,由于某种原因不符合您当前的要求。

      在 (2) 或 (3) 的情况下,您可以通过index hint sytax 诱使 MySQL 使用索引,但如果这样做,请务必运行一些测试以确定使用索引是否确实提高了性能你暗示它。

      【讨论】:

        【解决方案8】:
        ALTER TABLE TABLE_NAME ADD INDEX (COLUMN_NAME);
        

        【讨论】:

        • 在 MySQL 中,如果您使用 ALTER TABLE tbl ADD INDEX (col) 而不是 ALTER TABLE tbl ADD INDEX col (col),那么多次使用 ALTER TABLE tbl ADD INDEX (col) 将不断添加名为 col_2,col_3,... 的索引。而第二次使用ALTER TABLE tbl ADD INDEX col (col),将提供ERROR 1061 (42000): Duplicate key name 'col'
        猜你喜欢
        • 2014-07-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-11
        • 1970-01-01
        相关资源
        最近更新 更多