MySQL查询优化大表

时间:2014-06-16 19:20:56

标签: mysql bigdata

我无法找到一种方法来将简单查询固定在一个巨大的表格中。 我不认为我对MySQL有些疯狂,即使有大量的数据......我也无法理解为什么这些后续查询的执行时间会有这么多不同!

我尽力阅读有关mysql中的大数据,字段优化的所有文章,并且已经实现了减少字段类型的查询时间......但实际上,我现在迷失了这种简单的查询! / p>

这是关于MySQL 5.1.69的一个例子:

SELECT rv.`id_prd`,SUM(`quantite`)
FROM `report_ventes` AS rv 
WHERE `periode` BETWEEN 201301 AND 201312
GROUP BY rv.`id_prd` 
  

执行时间:3.76秒

让我们添加LEFT JOIN和另一个选定字段:

SELECT rv.`id_prd`,SUM(`quantite`),`acl_cip_7`
FROM `report_ventes` AS rv 
LEFT JOIN `report_produits` AS rp 
ON (rv.`id_prd` = rp.`id_prd`)
WHERE `periode` BETWEEN 201301 AND 201312
GROUP BY rv.`id_prd` 
  

执行时间:12.10秒

解释:

+----+-------------+-------+--------+---------------+---------+---------+--------------------------+----------+----------------------------------------------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref                      | rows     | Extra                                        |
+----+-------------+-------+--------+---------------+---------+---------+--------------------------+----------+----------------------------------------------+
|  1 | SIMPLE      | rv    | ALL    | periode       | NULL    | NULL    | NULL                     | 16556188 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | rp    | eq_ref | PRIMARY       | PRIMARY | 4       | main_reporting.rv.id_prd |        1 | Using index                                  |
+----+-------------+-------+--------+---------------+---------+---------+--------------------------+----------+----------------------------------------------+

让另一个where子句:

SELECT rv.`id_prd`,SUM(`quantite`),`acl_cip_7`
FROM `report_ventes` AS rv 
LEFT JOIN `report_produits` AS rp 
ON (rv.`id_prd` = rp.`id_prd`)
WHERE rp.`id_clas_prd` LIKE '1%'
AND `periode` BETWEEN 201301 AND 201312
GROUP BY rv.`id_prd` 
  

执行时间:21.00秒

解释:

+----+-------------+-------+--------+---------------------+---------+---------+--------------------------+----------+----------------------------------------------+
| id | select_type | table | type   | possible_keys       | key     | key_len | ref                      | rows     | Extra                                        |
+----+-------------+-------+--------+---------------------+---------+---------+--------------------------+----------+----------------------------------------------+
|  1 | SIMPLE      | rv    | ALL    | periode             | NULL    | NULL    | NULL                     | 16556188 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | rp    | eq_ref | PRIMARY,id_clas_prd | PRIMARY | 4       | main_reporting.rv.id_prd |        1 | Using where                                  |
+----+-------------+-------+--------+---------------------+---------+---------+--------------------------+----------+----------------------------------------------+

以下是表格参数:

report_produits:80 000行

CREATE TABLE `report_produits` (
  `id_prd` int(11) unsigned NOT NULL,
  `acl_cip_7` int(7) NOT NULL,
  `acl_cip_ean_13` varchar(255) DEFAULT NULL,
  `lib_prd` varchar(255) DEFAULT NULL,
  `id_clas_prd` char(7) NOT NULL DEFAULT '',
  `id_lab_prd` int(11) unsigned NOT NULL,
  `id_rbt_prd` int(11) unsigned NOT NULL,
  `id_tva_prd` int(11) unsigned NOT NULL,
  `t_gen` varchar(255) NOT NULL,
  `id_grp_gen` varchar(16) NOT NULL DEFAULT '',
  `id_liste_delivrance` int(11) unsigned NOT NULL,
  PRIMARY KEY (`id_prd`),
  KEY `index_lab` (`id_lab_prd`),
  KEY `index_grp` (`id_grp_gen`),
  KEY `id_clas_prd` (`id_clas_prd`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

report_ventes:16 556 188行

CREATE TABLE `report_ventes` (
  `id` int(13) NOT NULL AUTO_INCREMENT,
  `periode` mediumint(6) DEFAULT NULL,
  `id_phie` smallint(4) unsigned NOT NULL,
  `id_prd` mediumint(8) unsigned NOT NULL,
  `quantite` smallint(11) DEFAULT NULL,
  `ca_ht` decimal(10,2) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `periode` (`periode`)
) ENGINE=MyISAM AUTO_INCREMENT=18491315 DEFAULT CHARSET=utf8;

2 个答案:

答案 0 :(得分:1)

没有覆盖索引,MySQL决定扫描整个表比使用索引和查找请求的值更有效。

您正在加入report_ventes上的id_prd,但该列不是群集索引(MySQL中的PK)的一部分。这意味着,服务器应查找所有值。服务器可能会绕过periode索引,因为它没有足够的选择性来使用它。

索引可以提供帮助,其中包括id_prdperiodequantite列。使用此索引,MySQL服务器可能会使用它,因为它是此查询的覆盖索引。

尝试一下,但如果不在实际环境中进行测试,很难说出真相。

答案 1 :(得分:0)

基本上你的索引没有被使用,我没有在sql服务器上尝试它找不到确切的原因,但是一个常见的原因是数据有不同的类型。

AND periode BETWEEN 201301 AND 201312

“periode”的数据类型为mediumint(6),可能的“201301”数据类型为int(10)

LEFT JOIN `report_produits` AS rp ON (rv.`id_prd` = rp.`id_prd`)

以下是两种不同的数据类型。