Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/83.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 无法使用此表实现覆盖索引(2个等式和一个选择)?_Mysql_Sql_Optimization_Indexing - Fatal编程技术网

Mysql 无法使用此表实现覆盖索引(2个等式和一个选择)?

Mysql 无法使用此表实现覆盖索引(2个等式和一个选择)?,mysql,sql,optimization,indexing,Mysql,Sql,Optimization,Indexing,我在FAMILY、CUSTOMER\u id和AMOUNT上添加了一个封面索引IDX\u FAMILY\u CUSTOMER\u AMOUNT,因为大多数时候我使用以下查询: CREATE TABLE `discount_base` ( `id` varchar(12) COLLATE utf8_unicode_ci NOT NULL, `amount` decimal(13,4) NOT NULL, `description` varchar(255) COLLATE utf8_u

我在
FAMILY
CUSTOMER\u id
AMOUNT
上添加了一个封面索引
IDX\u FAMILY\u CUSTOMER\u AMOUNT
,因为大多数时候我使用以下查询:

CREATE TABLE `discount_base` (
  `id` varchar(12) COLLATE utf8_unicode_ci NOT NULL,
  `amount` decimal(13,4) NOT NULL,
  `description` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `family` varchar(4) COLLATE utf8_unicode_ci NOT NULL,
  `customer_id` varchar(8) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_CUSTOMER` (`customer_id`),
  KEY `IDX_FAMILY_CUSTOMER_AMOUNT` (`family`,`customer_id`,`amount`),
  CONSTRAINT `FK_CUSTOMER` FOREIGN KEY (`customer_id`) 
      REFERENCES `customer` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
然而,使用
EXPLAIN
和记录反弹(~250000)它会说:

为什么我越来越使用where;使用索引而不是仅仅使用索引

编辑:使用少量数据(使用where;使用index):

另一个
id
family
+
customer\u id
const):


是家庭和客户id字符串吗?我猜您可能会将customer_id作为一个整数传递,这可能会导致发生类型转换,因此索引不会用于该特定列

确保将客户机ID作为字符串传递,或考虑将表更改为存储CutOMLSID作为INT/< P>


如果您使用的是字母数字标识,那么这不适用。

我非常确定
使用索引是重要的部分,它意味着“使用覆盖索引”

需要进一步检查的两件事:

EXPLAIN SELECT amount
FROM discount_base
WHERE `id` = '060320000275';
可能会提供进一步的线索

EXPLAIN FORMT=JSON SELECT ...
将显示以各种方式读取/写入/等的行数。如果某个数字表示大约250000(在您的情况下),则表示表扫描。如果所有的数字都很小(大约是查询返回的行数),那么您可以确信它确实有效地执行了该查询

这里的数字并不区分对索引的读取和对数据的读取。但它们忽略了缓存。由于缓存的原因,计时(两次相同的运行)可能会显著不同;处理程序%的值不会更改。

上的
解释有这样一句话:

使用索引

使用从表中检索列信息 只显示索引树中的信息,而无需执行其他操作 尝试读取实际行。查询时可以使用此策略 仅使用作为单个索引一部分的列

如果额外的列 还表示使用where,这意味着索引用于执行 关键字值的查找。如果不使用where,优化器可能会 读取索引以避免读取数据行,但不将其用于 查找。例如,如果索引是查询的覆盖索引, 优化器可以扫描它而不使用它进行查找

根据您提供的信息,我的最佳猜测是,优化器首先使用您的
IDX\u客户
索引,然后执行键查找,根据键(客户id)从实际数据页检索非键数据(金额和系列)。 这很可能是由于索引中列的基数(例如唯一性)造成的。你应该检查 在where子句中使用的列,并将基数最高的列放在索引的第一位。从专栏猜 名称和当前结果,
customer\u id
的基数最高

因此,改变这一点:

FLUSH STATUS;
SELECT ...;
SHOW SESSION STATUS LIKE 'Handler%';
为此:

KEY `IDX_FAMILY_CUSTOMER_AMOUNT` (`family`,`customer_id`,`amount`)
进行更改后,应运行
ANALYZE TABLE
更新表统计信息。这将更新表统计信息,它可以
影响优化器对索引的选择。

这听起来不错。根据报告:

如果额外的列还显示Using where,则表示索引正在 用于执行键值的查找。如果不使用where,则 优化器可能正在读取索引以避免读取数据行,但不会 使用它进行查找。例如,如果索引是覆盖索引 对于查询,优化器可以扫描它,而不使用它进行查找


这意味着,单独使用索引将读取整个索引以检索结果,而不是使用索引结构来查找特定值。您可能可以通过
选择系列、客户id、折扣基数中的金额
获得此信息。在何处使用;使用索引意味着优化器利用索引查找和检索与查询参数(族、客户id)匹配的行。

问题的答案取决于引擎实际使用索引的目的

在给定的查询中,您要求引擎:

  • 查找值(其中/连接)
  • 基于此查找结果检索信息(选择)
  • 对于第一部分,一旦过滤结果(查找),在
    Extra
    中就会有一个条目指示
    使用WHERE
    ,因此这就是您在解释计划中看到它的原因

    对于第二部分,引擎不需要超出给定的索引,因为它是一个覆盖索引。解释计划通过使用索引显示
    来通知它。此
    使用索引
    提示与
    使用WHERE
    相结合,意味着您的索引也用于查询的查找部分,如mysql文档中所述:

    使用索引

    从表中检索列信息时仅使用 索引树中的信息,而不必进行额外的查找 读取实际行。当查询使用 仅限作为单个索引一部分的列

    如果额外的列还显示Using where,则表示索引正在 用于执行键值的查找。如果不使用where,则 优化器可能正在读取索引以避免读取数据行,但不会 使用它进行查找。例如,如果索引是覆盖索引 对于查询,优化器可以扫描它,而不使用它进行查找

    检查这把小提琴:


    我删除了where子句,现在查询仅使用索引显示
    。这是因为不需要在表中进行查找。

    这确实可能是个问题

    请注意,使用
    utf8\u unicode\u ci
    排序规则,单个索引键可能会匹配数百万个字符串。例如,所有这些字母都与b匹配
    EXPLAIN FORMT=JSON SELECT ...
    
    FLUSH STATUS;
    SELECT ...;
    SHOW SESSION STATUS LIKE 'Handler%';
    
    KEY `IDX_FAMILY_CUSTOMER_AMOUNT` (`family`,`customer_id`,`amount`)
    
    KEY `IDX_FAMILY_CUSTOMER_AMOUNT` (`customer_id`,`family`,`amount`)
    
    SELECT amount
    FROM discount_base
    WHERE family = :family AND customer_id = :customer_id;
    
    WHERE family in (lower(:family, upper(:family), . . .) and . . . 
    
    KEY IDX_CUSTOMERFAMILY_AMOUNT (CustomerFamily, amount)
    
    KEY `IDX_FAMILY_CUSTOMER_AMOUNT` (`family`,`customer_id`)
    
     USE INDEX (`IDX_FAMILY_CUSTOMER_AMOUNT`)
    
    SELECT amount FROM discount_base 
    USE INDEX (`IDX_FAMILY_CUSTOMER_AMOUNT`)
    WHERE family = '1' AND customer_id = '1'