我正在尝试在一个巨大的MySQL-Table(超过38.700.000行)上加速我的查询,但我无法弄清楚要做什么。我阅读了几十篇相关的文章,甚至还搞乱了MySQL文档。 我承认,我需要帮助!
这是我目前的表格结构:
CREATE TABLE `bz_all_part` (
`salon` smallint(6) unsigned NOT NULL DEFAULT '0',
`datum` int(10) unsigned NOT NULL DEFAULT '936868149',
`datumuhrzeit` int(10) unsigned NOT NULL DEFAULT '936868149',
`ma` mediumint(6) unsigned NOT NULL DEFAULT '0',
`ztyp` int(10) unsigned NOT NULL DEFAULT '0',
`zart` int(10) unsigned NOT NULL DEFAULT '0',
`storno` tinyint(1) unsigned NOT NULL DEFAULT '0',
`betrag` int(10) NOT NULL DEFAULT '0',
`betragorig` int(10) NOT NULL DEFAULT '0',
KEY `test1` (`ztyp`,`storno`,`ma`),
KEY `test2` (`ztyp`,`storno`),
KEY `test3` (`ma`),
KEY `test4` (`ztyp`,`datum`),
KEY `test5` (`datumuhrzeit`,`ztyp`,`storno`),
KEY `test6` (`ma`,`ztyp`,`datumuhrzeit`),
KEY `test7` (`ztyp`,`storno`,`datumuhrzeit`),
KEY `test8` (`ztyp`,`storno`,`datumuhrzeit`,`zart`),
KEY `test9` (`salon`,`ma`,`zart`,`ztyp`,`storno`,`datumuhrzeit`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
/*!50100 PARTITION BY RANGE (datumuhrzeit)
(PARTITION s0 VALUES LESS THAN (1391210639) ENGINE = MyISAM,
PARTITION s1 VALUES LESS THAN (1393889039) ENGINE = MyISAM,
...
PARTITION s47 VALUES LESS THAN (1514762639) ENGINE = MyISAM) */;
字段 **数据** 和 ** datumuhrzeit ** 是Unix-Timestamps。我认为它们比 datetime 更快。
正如您所看到的,我有很多分区(当我选择较小的句点时,它们会加快查询速度)和一些测试索引。他们帮助不大。
我读了很多关于多列索引中的列应该是正确的顺序(因为它们在查询中使用)。我尝试使用索引 test7 和 test9 ,但我没有运气。
这是我使用的查询:
SELECT
*,
ROUND(betrag / anzBelege, 2) as umsJeBeleg,
ROUND(betragorig / anzBelege, 2) as umsJeBelegOrig
FROM
(SELECT
count(distinct concat(salon, datumuhrzeit)) as anzBelege,
SUM(zart) as anzServices,
SUM(ROUND(betrag / 100, 2)) as betrag,
SUM(ROUND(betragorig / 100, 2)) as betragorig
FROM
bz_all_part
WHERE
ztyp = 0
AND
storno = 0
AND
datumuhrzeit >= unix_timestamp("2013-01-01 00:00:00")
AND
datumuhrzeit <= unix_timestamp("2018-07-01 00:00:00")
GROUP BY
salon,
ma,
zart) core
当我运行此查询时,结果包含526607行,大约需要206秒。
解释输出:
id|select_type|table |type|possible_keys |key |key_len|ref |rows |Extra
--|-----------|-----------|----|-----------------|-----|-------|-----------|--------|-----
1 |PRIMARY |<derived2> |ALL |NULL |NULL |NULL |NULL |22955178|NULL
2 |DERIVED |bz_all_part|ref |test1,2,4,5,7,8,9|test2|5 |const,const|22955178|Using where; Using filesort
可能的密钥 包含索引test7和test9,但它既不使用它们,也使用test2。我不明白为什么!
我非常感谢有关此主题的一些帮助。
非常感谢!
其他信息:
编辑1:
输出:
SELECT * FROM bz_all_part PROCEDURE ANALYSE();
Field_name |Min_value| Max_value|Min_length|Max_length|Empties_or_zeros|Nulls|Avg_value_or_avg_length|Std |Optimal_fieldtype
----------------------------|---------|----------|----------|----------|----------------|-----|-----------------------|-----------|-----------------------------
db.bz_all_part.salon |0 |60974 |1 |5 |1 |0 |13357.9473 |17056.3346 |SMALLINT(5) UNSIGNED NOT NULL
db.bz_all_part.datum |0 |1490911200|1 |10 |1 |0 |1440703052.6328 |427695.2284|INT(10) UNSIGNED NOT NULL
db.bz_all_part.datumuhrzeit |0 |1490989761|1 |10 |1 |0 |1440755042.1115 |460817.3074|INT(10) UNSIGNED NOT NULL
db.bz_all_part.ma |0 |60127 |1 |5 |43 |0 |1166.8595 |7840.3516 |SMALLINT(5) UNSIGNED NOT NULL
db.bz_all_part.ztyp |0 |40181 |1 |5 |26257963 |0 |1140.0327 |4650.5316 |SMALLINT(5) UNSIGNED NOT NULL
db.bz_all_part.zart |0 |55158 |1 |5 |1 |0 |3338.9947 |8165.2681 |SMALLINT(5) UNSIGNED NOT NULL
db.bz_all_part.storno |0 |2 |1 |1 |38604746 |0 |0.0074 |0.1111 |ENUM('0','1','2') NOT NULL
db.bz_all_part.betrag |-45240 |269900 |1 |6 |2123326 |0 |1438.2915 |1916.8851 |MEDIUMINT(6) NOT NULL
db.bz_all_part.betragorig |-45240 |1711250 |1 |7 |2546610 |0 |1491.6800 |2089.4486 |MEDIUMINT(7) NOT NULL
编辑2:
CREATE TABLE `bz_all_part2` (
`salon` smallint(6) unsigned NOT NULL DEFAULT '0',
`datum` timestamp NOT NULL,
`datumuhrzeit` timestamp NOT NULL,
`ma` mediumint(6) unsigned NOT NULL DEFAULT '0',
`ztyp` int(10) unsigned NOT NULL DEFAULT '0',
`zart` int(10) unsigned NOT NULL DEFAULT '0',
`storno` enum('0','1','2') DEFAULT NULL,
`betrag` mediumint(7) NOT NULL DEFAULT '0',
`betragorig` mediumint(7) NOT NULL DEFAULT '0',
KEY `test1` (`ztyp`,`storno`,`datum`,`zart`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
新解释输出:
id|select_type|table |type|possible_keys |key |key_len|ref |rows |Extra
--|-----------|-----------|----|-----------------|-----|-------|-----------|--------|-----
1 |PRIMARY |<derived2> |ALL |NULL |NULL |NULL |NULL |2243987 |NULL
2 |DERIVED |bz_all_part|ref |test1 |test1|6 |const,const|2243987 |Using index condition; Using where; Using filesort
输出:
SELECT * FROM bz_all_part PROCEDURE ANALYSE();
与上述几乎相同
我将表格缩小为 5.000.000 行以获得更快的结果。
还有什么想法吗?
答案 0 :(得分:0)
KEY `test1` (`ztyp`,`storno`,`ma`),
KEY `test2` (`ztyp`,`storno`),
第二个是多余的,因为它是第一个的前缀,放弃它。
切换到InnoDB 并提供PRIMARY KEY
。 MyISAM将在下一个版本中消失。
将storno
从TINYINT
更改为ENUM
不会影响表格大小或查询效果。但是,更改为NULL
可能会产生很小的负面影响。
48个分区可能将查询放慢一些,而不是加快速度。您已拥有“完美”索引:(ztyp
,storno
,datumuhrzeit
)。
“526607行206秒” - 但是要扫描多少行来执行子查询?我想,那是代价高昂的部分。事实上,为什么不把子查询拉出来,把它计算在内;那么如果它是总数的大部分,那就让我们专注于它。
但是,够了。可能这个就是答案......
构建并维护摘要表。
它可能会,也许......
PRIMARY KEY(salon, ztyp, storno, month)
SUM(zart) AS sum_zart
SUM(...) etc
将month
datumuhrzeit
截断到月份(或一天或任何有意义的事情)。
想一想这样的表是否会让你运行子查询。
这可能会以10倍的速度运行内部查询。