mysql 查询使用了错误的索引
mysql query using the wrong indexes
我在 mysql 数据库中的一些查询有一些优化问题。在构建我的应用程序后,我尝试使用 mysqltuner 进行优化并进行解释,以查找非索引查询。这是一个经常 运行 并且报告未使用索引的查询:
SELECT count(*) AS rangedandselling
FROM
( SELECT DISTINCT `store_formats`.`Store Name`
FROM (`eds_sales`
JOIN `store_formats`
ON (`eds_sales`.`Store Nbr` = `store_formats`.`Store Nbr`)
)
WHERE `eds_sales`.`Prime Item Nbr` = '4'
AND `eds_sales`.`Date` BETWEEN CAST('2016-07-14' AS DATETIME)
AND CAST('2016-07-21' AS DATETIME)
AND `store_formats`.`Format Name` IN ('format1','format2')
AND `store_formats`.`Store Name` IN (
SELECT DISTINCT `store_formats`.`Store Name`
FROM (`eds_stock`
JOIN `store_formats`
ON (`eds_stock`.`Store Nbr` = `store_formats`.`Store Nbr`)
)
WHERE `eds_stock`.`Prime Item Nbr` = '4'
AND `eds_stock`.`Date` BETWEEN CAST('2016-07-14' AS DATETIME)
AND CAST('2016-07-21' AS DATETIME)
AND `store_formats`.`Format Name` IN ('format1','format2')
AND `eds_stock`.`Curr Traited Store/Item Comb.` = '1' )
) t
这是解释输出:https://tools.mariadb.org/ea/pyb3h
虽然我已经为连接和查找中涉及的列建立了索引,但看起来它正在选择另一个索引。这个另一个索引称为 uniqness,由我用于插入的源列中的 6 个不同列组成(这些列的组合是唯一使行唯一的东西,因此我给出了这个名称。)。然后我确保我有其他列的索引,并且我可以在解释中看到它们。我不确定为什么会这样,有人可以帮忙吗?
关于优化此查询有什么想法吗?
上面的 link 不起作用的解释如下:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+---+---+---+---+---+---+---+---+---+---+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 167048 | |
| 2 | DERIVED | eds_sales | ref | uniqness,Prime Item Nbr,Store Nbr | uniqness | 4 | const | 23864 | Using where; Using index; Using temporary |
| 2 | DERIVED | store_formats | ref | Store Nbr,Store Name,Format Name | Store Nbr | 5 | equidata.eds_sales.Store Nbr | 1 | Using where |
| 2 | DERIVED | <subquery3> | eq_ref | distinct_key | distinct_key | 84 | func | 1 | Distinct |
| 3 | MATERIALIZED | store_formats | ALL | Store Nbr,Store Name,Format Name | NULL | NULL | NULL | 634 | Using where; Distinct |
| 3 | MATERIALIZED | eds_stock | ref | uniqness,Prime Item Nbr,Store Nbr | uniqness | 8 | const,equidata.store_formats.Store Nbr | 7 | Using where; Distinct |
+---+---+---+---+---+---+---+---+---+---+
我也发布了相关的 tables 结构 :
--
-- Table structure for table `eds_sales`
--
CREATE TABLE `eds_sales` (
`id` int(12) NOT NULL,
`Prime Item Nbr` int(12) NOT NULL,
`Prime Item Desc` varchar(255) NOT NULL,
`Prime Size Desc` varchar(255) NOT NULL,
`Variety` varchar(255) NOT NULL,
`WHPK Qty` int(5) NOT NULL,
`SUPPK Qty` int(5) NOT NULL,
`Depot Nbr` int(5) NOT NULL,
`Depot Name` varchar(255) NOT NULL,
`Store Nbr` int(5) NOT NULL,
`Store Name` varchar(255) NOT NULL,
`EPOS Quantity` int(5) NOT NULL,
`EPOS Sales` float(4,2) NOT NULL,
`Date` date NOT NULL,
`Client` varchar(255) NOT NULL,
`Retailer` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `eds_sales`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `uniqness` (`Prime Item Nbr`,`Prime Item Desc`,`Prime Size Desc`,`Variety`,`WHPK Qty`,`SUPPK Qty`,`Depot Nbr`,`Depot Name`,`Store Nbr`,`Store Name`,`Date`,`Client`) USING BTREE,
ADD KEY `Prime Item Nbr` (`Prime Item Nbr`),
ADD KEY `Store Nbr` (`Store Nbr`);
Table table eds_stock
的结构
CREATE TABLE `eds_stock` (
`Prime Item Nbr` int(12) NOT NULL,
`Prime Item Desc` varchar(255) NOT NULL,
`Prime Size Desc` varchar(255) NOT NULL,
`Variety` varchar(255) NOT NULL,
`Curr Valid Store/Item Comb.` int(12) NOT NULL,
`Curr Traited Store/Item Comb.` int(12) NOT NULL,
`Store Nbr` int(12) NOT NULL,
`Store Name` varchar(255) NOT NULL,
`Curr Str On Hand Qty` int(12) NOT NULL,
`Curr Str In Transit Qty` int(12) NOT NULL,
`Curr Str On Order Qty` int(12) NOT NULL,
`Curr Str In Depot Qty` int(12) NOT NULL,
`Curr Instock %` int(12) NOT NULL,
`Max Shelf Qty` int(12) NOT NULL,
`On Hand Qty` int(12) NOT NULL,
`Date` date NOT NULL,
`Client` varchar(255) NOT NULL,
`Retailer` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `eds_stock`
ADD UNIQUE KEY `uniqness` (`Prime Item Nbr`,`Store Nbr`,`Date`,`Client`,`Retailer`),
ADD KEY `Prime Item Nbr` (`Prime Item Nbr`),
ADD KEY `Store Nbr` (`Store Nbr`),
ADD KEY `Curr Valid Store/Item Comb.` (`Curr Valid Store/Item Comb.`);
Table table store_formats
的结构
CREATE TABLE `store_formats` (
`id` int(12) NOT NULL,
`Store Nbr` int(4) DEFAULT NULL,
`Store Name` varchar(27) DEFAULT NULL,
`City` varchar(19) DEFAULT NULL,
`Post Code` varchar(9) DEFAULT NULL,
`Region #` int(2) DEFAULT NULL,
`Region Name` varchar(10) DEFAULT NULL,
`Distr #` int(3) DEFAULT NULL,
`Dist Name` varchar(26) DEFAULT NULL,
`Square Footage` varchar(7) DEFAULT NULL,
`Format` int(1) DEFAULT NULL,
`Format Name` varchar(23) DEFAULT NULL,
`Store Type` varchar(20) DEFAULT NULL,
`TV Region` varchar(12) DEFAULT NULL,
`Pharmacy` varchar(3) DEFAULT NULL,
`Optician` varchar(3) DEFAULT NULL,
`Home Shopping` varchar(3) DEFAULT NULL,
`Retailer` varchar(15) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `store_formats`
ADD PRIMARY KEY (`id`),
ADD KEY `Store Nbr` (`Store Nbr`),
ADD KEY `Store Name` (`Store Name`),
ADD KEY `Format Name` (`Format Name`);
CAST('2016-07-14' AS DATETIME)
-- CAST
不需要; '2016-07-14'
工作正常。 (特别是因为您正在与 DATE 进行比较。)
IN ( SELECT ... )
效率低下。更改为 JOIN
.
在 eds_stock
,而不是
INDEX(`Prime Item Nbr`)
有这两个:
INDEX(`Prime Item Nbr`, `Date`)
INDEX(`Prime Item Nbr`, `Curr Traited Store/Item Comb.`, `Date`)
INT
始终是一个 4 字节的数字,即使您说 int(2)
。考虑切换到 TINYINT UNSIGNED
(以及 INT
的其他尺寸)。
float(4,2)
-- 不要使用(m,n)
;它会导致额外的舍入和我不希望的截断。要么使用 DECIMAL(4,2)
(为了钱),要么使用普通的 FLOAT
.
错误??你真的想要 8 天,而不是一周
AND `Date` BETWEEN CAST('2016-07-14' AS DATETIME) AND CAST('2016-07-21' AS DATETIME)
我喜欢这个图案:
AND `Date` >= '2016-07-14'
AND `Date` < '2016-07-14' + INTERVAL 1 WEEK
而不是两个 select
SELECT count(*) AS rangedandselling
FROM ( SELECT DISTINCT `store_formats`.`Store Name` ...
一个 select 可能会起作用(并且更快):
SELECT COUNT(DISTINCT `store_formats`.`Store Name`) AS rangedandselling ...
一旦您清理了其中的大部分内容,如果仍有问题,我们可以回到您关于 'wrong index' 的问题。 (如果您需要进一步的帮助,请开始一个新的问题。)
我在 mysql 数据库中的一些查询有一些优化问题。在构建我的应用程序后,我尝试使用 mysqltuner 进行优化并进行解释,以查找非索引查询。这是一个经常 运行 并且报告未使用索引的查询:
SELECT count(*) AS rangedandselling
FROM
( SELECT DISTINCT `store_formats`.`Store Name`
FROM (`eds_sales`
JOIN `store_formats`
ON (`eds_sales`.`Store Nbr` = `store_formats`.`Store Nbr`)
)
WHERE `eds_sales`.`Prime Item Nbr` = '4'
AND `eds_sales`.`Date` BETWEEN CAST('2016-07-14' AS DATETIME)
AND CAST('2016-07-21' AS DATETIME)
AND `store_formats`.`Format Name` IN ('format1','format2')
AND `store_formats`.`Store Name` IN (
SELECT DISTINCT `store_formats`.`Store Name`
FROM (`eds_stock`
JOIN `store_formats`
ON (`eds_stock`.`Store Nbr` = `store_formats`.`Store Nbr`)
)
WHERE `eds_stock`.`Prime Item Nbr` = '4'
AND `eds_stock`.`Date` BETWEEN CAST('2016-07-14' AS DATETIME)
AND CAST('2016-07-21' AS DATETIME)
AND `store_formats`.`Format Name` IN ('format1','format2')
AND `eds_stock`.`Curr Traited Store/Item Comb.` = '1' )
) t
这是解释输出:https://tools.mariadb.org/ea/pyb3h
虽然我已经为连接和查找中涉及的列建立了索引,但看起来它正在选择另一个索引。这个另一个索引称为 uniqness,由我用于插入的源列中的 6 个不同列组成(这些列的组合是唯一使行唯一的东西,因此我给出了这个名称。)。然后我确保我有其他列的索引,并且我可以在解释中看到它们。我不确定为什么会这样,有人可以帮忙吗?
关于优化此查询有什么想法吗?
上面的 link 不起作用的解释如下:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+---+---+---+---+---+---+---+---+---+---+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 167048 | |
| 2 | DERIVED | eds_sales | ref | uniqness,Prime Item Nbr,Store Nbr | uniqness | 4 | const | 23864 | Using where; Using index; Using temporary |
| 2 | DERIVED | store_formats | ref | Store Nbr,Store Name,Format Name | Store Nbr | 5 | equidata.eds_sales.Store Nbr | 1 | Using where |
| 2 | DERIVED | <subquery3> | eq_ref | distinct_key | distinct_key | 84 | func | 1 | Distinct |
| 3 | MATERIALIZED | store_formats | ALL | Store Nbr,Store Name,Format Name | NULL | NULL | NULL | 634 | Using where; Distinct |
| 3 | MATERIALIZED | eds_stock | ref | uniqness,Prime Item Nbr,Store Nbr | uniqness | 8 | const,equidata.store_formats.Store Nbr | 7 | Using where; Distinct |
+---+---+---+---+---+---+---+---+---+---+
我也发布了相关的 tables 结构 :
--
-- Table structure for table `eds_sales`
--
CREATE TABLE `eds_sales` (
`id` int(12) NOT NULL,
`Prime Item Nbr` int(12) NOT NULL,
`Prime Item Desc` varchar(255) NOT NULL,
`Prime Size Desc` varchar(255) NOT NULL,
`Variety` varchar(255) NOT NULL,
`WHPK Qty` int(5) NOT NULL,
`SUPPK Qty` int(5) NOT NULL,
`Depot Nbr` int(5) NOT NULL,
`Depot Name` varchar(255) NOT NULL,
`Store Nbr` int(5) NOT NULL,
`Store Name` varchar(255) NOT NULL,
`EPOS Quantity` int(5) NOT NULL,
`EPOS Sales` float(4,2) NOT NULL,
`Date` date NOT NULL,
`Client` varchar(255) NOT NULL,
`Retailer` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE `eds_sales`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `uniqness` (`Prime Item Nbr`,`Prime Item Desc`,`Prime Size Desc`,`Variety`,`WHPK Qty`,`SUPPK Qty`,`Depot Nbr`,`Depot Name`,`Store Nbr`,`Store Name`,`Date`,`Client`) USING BTREE,
ADD KEY `Prime Item Nbr` (`Prime Item Nbr`),
ADD KEY `Store Nbr` (`Store Nbr`);
Table table eds_stock
CREATE TABLE `eds_stock` (
`Prime Item Nbr` int(12) NOT NULL,
`Prime Item Desc` varchar(255) NOT NULL,
`Prime Size Desc` varchar(255) NOT NULL,
`Variety` varchar(255) NOT NULL,
`Curr Valid Store/Item Comb.` int(12) NOT NULL,
`Curr Traited Store/Item Comb.` int(12) NOT NULL,
`Store Nbr` int(12) NOT NULL,
`Store Name` varchar(255) NOT NULL,
`Curr Str On Hand Qty` int(12) NOT NULL,
`Curr Str In Transit Qty` int(12) NOT NULL,
`Curr Str On Order Qty` int(12) NOT NULL,
`Curr Str In Depot Qty` int(12) NOT NULL,
`Curr Instock %` int(12) NOT NULL,
`Max Shelf Qty` int(12) NOT NULL,
`On Hand Qty` int(12) NOT NULL,
`Date` date NOT NULL,
`Client` varchar(255) NOT NULL,
`Retailer` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `eds_stock`
ADD UNIQUE KEY `uniqness` (`Prime Item Nbr`,`Store Nbr`,`Date`,`Client`,`Retailer`),
ADD KEY `Prime Item Nbr` (`Prime Item Nbr`),
ADD KEY `Store Nbr` (`Store Nbr`),
ADD KEY `Curr Valid Store/Item Comb.` (`Curr Valid Store/Item Comb.`);
Table table store_formats
CREATE TABLE `store_formats` (
`id` int(12) NOT NULL,
`Store Nbr` int(4) DEFAULT NULL,
`Store Name` varchar(27) DEFAULT NULL,
`City` varchar(19) DEFAULT NULL,
`Post Code` varchar(9) DEFAULT NULL,
`Region #` int(2) DEFAULT NULL,
`Region Name` varchar(10) DEFAULT NULL,
`Distr #` int(3) DEFAULT NULL,
`Dist Name` varchar(26) DEFAULT NULL,
`Square Footage` varchar(7) DEFAULT NULL,
`Format` int(1) DEFAULT NULL,
`Format Name` varchar(23) DEFAULT NULL,
`Store Type` varchar(20) DEFAULT NULL,
`TV Region` varchar(12) DEFAULT NULL,
`Pharmacy` varchar(3) DEFAULT NULL,
`Optician` varchar(3) DEFAULT NULL,
`Home Shopping` varchar(3) DEFAULT NULL,
`Retailer` varchar(15) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `store_formats`
ADD PRIMARY KEY (`id`),
ADD KEY `Store Nbr` (`Store Nbr`),
ADD KEY `Store Name` (`Store Name`),
ADD KEY `Format Name` (`Format Name`);
CAST('2016-07-14' AS DATETIME)
-- CAST
不需要; '2016-07-14'
工作正常。 (特别是因为您正在与 DATE 进行比较。)
IN ( SELECT ... )
效率低下。更改为 JOIN
.
在 eds_stock
,而不是
INDEX(`Prime Item Nbr`)
有这两个:
INDEX(`Prime Item Nbr`, `Date`)
INDEX(`Prime Item Nbr`, `Curr Traited Store/Item Comb.`, `Date`)
INT
始终是一个 4 字节的数字,即使您说 int(2)
。考虑切换到 TINYINT UNSIGNED
(以及 INT
的其他尺寸)。
float(4,2)
-- 不要使用(m,n)
;它会导致额外的舍入和我不希望的截断。要么使用 DECIMAL(4,2)
(为了钱),要么使用普通的 FLOAT
.
错误??你真的想要 8 天,而不是一周
AND `Date` BETWEEN CAST('2016-07-14' AS DATETIME) AND CAST('2016-07-21' AS DATETIME)
我喜欢这个图案:
AND `Date` >= '2016-07-14'
AND `Date` < '2016-07-14' + INTERVAL 1 WEEK
而不是两个 select
SELECT count(*) AS rangedandselling
FROM ( SELECT DISTINCT `store_formats`.`Store Name` ...
一个 select 可能会起作用(并且更快):
SELECT COUNT(DISTINCT `store_formats`.`Store Name`) AS rangedandselling ...
一旦您清理了其中的大部分内容,如果仍有问题,我们可以回到您关于 'wrong index' 的问题。 (如果您需要进一步的帮助,请开始一个新的问题。)