Mysql 当列是复合键的一部分时未使用索引

Mysql 当列是复合键的一部分时未使用索引,mysql,indexing,query-performance,Mysql,Indexing,Query Performance,我有两个巨大的表,我从中选择了大量的数据 表存储采购订单详细信息和产品信息 PURCHASE_ORDER_DETAILS. CREATE TABLE `PURCHASE_ORDER_DETAILS` ( `PURCHASE_ORDER_NUMBER_PF` INT(20) NOT NULL, `PRODUCT_CODE_PF` VARCHAR(32) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL, `OR

我有两个巨大的表,我从中选择了大量的数据

表存储采购订单详细信息和产品信息

    PURCHASE_ORDER_DETAILS.
    CREATE TABLE `PURCHASE_ORDER_DETAILS` (
    `PURCHASE_ORDER_NUMBER_PF` INT(20) NOT NULL,
    `PRODUCT_CODE_PF` VARCHAR(32) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
    `ORDER_QUANTITY` INT(8) DEFAULT NULL,
    `UNIT_PRICE` DECIMAL(12,2) DEFAULT NULL,
    `ORDER_FULLFILLMENT_DUE_DATE` DATETIME DEFAULT NULL,
    `DELIVERY_ADDRESS` VARCHAR(64) CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL,
    `DELIVERY_CITY` VARCHAR(32) CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL,
     `DELIVERY_ZIP` BIGINT(10) DEFAULT NULL,
     `other columns`
      PRIMARY KEY (`PURCHASE_ORDER_NUMBER_PF`,`PRODUCT_CODE_PF`),
      KEY `RMAPWBTX_PUCH_ORDE_DLST_INDX` (`DELIVERY_STATE_ID_FK`),
      KEY `RMAPWBTX_PUCH_ORDE_DLTY_INDX` (`DELIVERY_TYPE_FK`),
      KEY `RMAPWBTX_PUCH_ORDE_TACO_INDX` (`TAX_CODE_FK`),
      KEY `RMAPWBMS_PUOR_DETL_PDCO_FK` (`PRODUCT_CODE_PF`),
      KEY `RMAPWBTX_PUOR_DETL_TACO_FK` (`TAX_CODE_FK`),
      KEY `CREATED_DATE_INDX` (`CREATED_DATE`),
      KEY `MODIFIED_DATE_INDX` (`MODIFIED_DATE`),
      CONSTRAINT `RMAPWBMS_PUOR_DETL_PDCO_FK` FOREIGN KEY (`PRODUCT_CODE_PF`) 
      REFERENCES `PRODUCT` (`PRODUCT_CODE_PK`) ON DELETE NO ACTION ON UPDATE NO ACTION,
      CONSTRAINT `RMAPWBMS_PUOR_DETL_PONU_FK` FOREIGN KEY 
      (`PURCHASE_ORDER_NUMBER_PF`) REFERENCES `PURCHASE_ORDER` 
      (`PURCHASE_ORDER_NUMBER_PK`),
     CONSTRAINT `RMAPWBTX_PO_DETL_DSID_FK` FOREIGN KEY 
     (`DELIVERY_STATE_ID_FK`) REFERENCES `STATE` (`STATE_ID_PK`),
     CONSTRAINT `RMAPWBTX_PUOR_DETL_TACO_FK` FOREIGN KEY (`TAX_CODE_FK`) 
     REFERENCES `TAX` (`TAX_CODE_PK`) ON DELETE NO ACTION ON UPDATE NO ACTION
     ) ENGINE=INNODB DEFAULT CHARSET=latin1;


PRODUCT

    CREATE TABLE `PRODUCT` (
    `PRODUCT_CODE_PK` VARCHAR(32) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
    `PRODUCT_DESC` VARCHAR(256) CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL,
    `FEE_BILL_CODE` VARCHAR(32) CHARACTER SET latin1 COLLATE latin1_bin DEFAULT NULL,
    `other columns`
     PRIMARY KEY (`PRODUCT_CODE_PK`),
     KEY `CREATED_DATE_INDX` (`CREATED_DATE`),
     KEY `MODIFIED_DATE_INDX` (`MODIFIED_DATE`),
     KEY `PRODUCT_EXCO_FK` (`EXPENSE_CODE_ID_FK`),
     KEY `FK_PRODUCT_ENTITY_TYPE` (`ENTITY_TYPE_CODE_FK`),
     CONSTRAINT `FK_PRODUCT_ENTITY_TYPE` FOREIGN KEY (`ENTITY_TYPE_CODE_FK`) REFERENCES `ENTITY_TYPE` (`ENTITY_TYPE_CODE_PK`)
     ) ENGINE=INNODB DEFAULT CHARSET=latin1

     Below query is taking ~10min to get ~1M records.

     EXPLAIN SELECT * FROM
     PURCHASE_ORDER_DETAILS POD
     JOIN PRODUCT PRD ON POD.PRODUCT_CODE_PF=PRD.PRODUCT_CODE_PK;
+----+-------------+-------+------+----------------------------+-----------------

    -----------+---------+-----------------------------------------------+-------+-------+
    | id | select_type | table | type | possible_keys              | key                        | key_len | ref                                           | rows  | Extra |
    +----+-------------+-------+------+----------------------------+----------------------------+---------+-----------------------------------------------+-------+-------+
    |  1 | SIMPLE      | PRD   | ALL  | PRIMARY                    | NULL                       | NULL    | NULL                                          | 14283 | NULL  |
    |  1 | SIMPLE      | POD   | ref  | RMAPWBMS_PUOR_DETL_PDCO_FK | RMAPWBMS_PUOR_DETL_PDCO_FK | 34      | REALREMIT_PROD_ALTISOURCE.PRD.PRODUCT_CODE_PK |    40 | NULL  |
    +----+-------------+-------+------+----------------------------+----------------------------+---------+-----------------------------------------------+-------+---
编辑1: 上面的查询是一个示例,下面是我试图获取1M条记录的实际查询(主表POD有22M条记录)

解释上述查询的输出

+----+-------------+-------+--------+-------------------------------------+----------------------------+---------+--------------------------------------------------------+-------+-------------+
| id | select_type | table | type   | possible_keys                       | key                        | key_len | ref                                                    | rows  | Extra       |
+----+-------------+-------+--------+-------------------------------------+----------------------------+---------+--------------------------------------------------------+-------+-------------+
|  1 | SIMPLE      | PRD   | ALL    | PRIMARY,PRODUCT_EXCO_FK             | NULL                       | NULL    | NULL                                                   | 14283 | NULL        |
|  1 | SIMPLE      | EXP   | eq_ref | PRIMARY                             | PRIMARY                    | 4       | REALREMIT_PROD_ALTISOURCE.PRD.EXPENSE_CODE_ID_FK       |     1 | NULL        |
|  1 | SIMPLE      | POD   | ref    | PRIMARY,RMAPWBMS_PUOR_DETL_PDCO_FK  | RMAPWBMS_PUOR_DETL_PDCO_FK | 34      | REALREMIT_PROD_ALTISOURCE.PRD.PRODUCT_CODE_PK          |    40 | NULL        |
|  1 | SIMPLE      | MPO   | ref    | MIGR_PO_NBR_INDX,MIGR_BATCH_ID_INDX | MIGR_PO_NBR_INDX           | 4       | REALREMIT_PROD_ALTISOURCE.POD.PURCHASE_ORDER_NUMBER_PF |     1 | Using where |
+----+-------------+-------+--------+-------------------------------------+----------------------------+---------+--------------------------------------------------------+-------+-------------+
4 rows in set (0.20 sec)
两个数据库具有相同的字符集 联接中使用的列具有相同的排序 两个表具有相同的字符集

我创建了一个新表,其中主键是连接列purcase\u ORDER\u NUMBER\u PF和PRODUCT\u CODE\u PF的,然后我在PRODUCT\u CODE\u PF上添加了一个新索引 在这种情况下是否将使用索引和/或这是在联接中使用索引的最佳方式

谢谢

这些可能会有帮助:

MPO:  INDEX(BATCH_ID, PURCHASE_ORDER_NUMBER_PK)   -- in this order
EXP:  INDEX(EXPENSE_CODE_ID_PK)   -- unless it is the PRIMARY KEY
但是,在不知道“某些专栏”中有什么内容的情况下,我无法预测它们会有多大帮助。对于MPO和EXP,让
显示创建表
会有所帮助


你有多少公羊?innodb\u buffer\u pool\u size的值是多少?我这样问是因为你可能会大发雷霆。

你有一本电话簿,上面有你镇上所有人的电话。你想给他们打电话。引用包含人名和姓氏的索引有什么意义吗?或者,当你试图调用所有人时,一页一页地查找索引是否更明智?这就是为什么你的索引没有被使用——它只是毫无意义,它什么也不做。您正在选择所有记录。@N.B.-请检查编辑,我又添加了一个具有相同问题的示例。MySQL optimizer是基于成本的,计算所需时间较少。。随机磁盘I/O非常昂贵,尤其是在使用普通HDD时。。不知道最新的MySQL优化器(8.0)是否能更好地使用SSD进行优化,或者是否能检测到SSD磁盘..因此MySQL在索引查找(14283随机磁盘I/O)上选择了全表扫描(1个随机磁盘I/O和顺序读取)。。。。。。想象一下,如果磁盘的寻道时间是10毫秒。全表扫描将在10毫秒内找到此信息。。索引查找将花费14283*10=142830ms,即2.3805分钟
EXPLAIN query FORMAT=JSON
将更好地了解执行某些不同查询计划所需的成本(如果您的MySQL版本支持的话)是否存在问题?我的意思是,如果这是缓慢的,这不是因为没有使用索引。索引有助于查找和排序数据。如果您选择并发送1M行,那么传输和接收的数据量将使此操作变慢。
MPO:  INDEX(BATCH_ID, PURCHASE_ORDER_NUMBER_PK)   -- in this order
EXP:  INDEX(EXPENSE_CODE_ID_PK)   -- unless it is the PRIMARY KEY