我附加了数据库的Schema。 当表Metrics具有多个技术和参数时,我遇到了强大的性能问题,因为我需要生成大量的连接SQL查询才能正确访问它们。一名工作人员建议迁移到MongoDB,但我想确保在MariaDB中没有更好的解决方案。查询示例:
SELECT DISTINCT metric.id, a2.xplotvarvalue, metric.joules, metric.seconds, metadata.data
FROM metric
JOIN concern ON concern.id=metric.idc AND concern.name = 'Security'
JOIN design ON design.id=metric.idd AND design.name = 'Cryptography'
JOIN datatype ON datatype.id=metric.iddt AND datatype.name = 'String'
JOIN operation ON operation.id=metric.ido AND operation.name = 'KeyGeneration'
JOIN technologymetric ON technologymetric.idm=metric.id
JOIN (SELECT idm FROM technologymetric JOIN technology ON technology.id = technologymetric.idt AND technology.name = 'AIAK') AS a0
ON a0.idm = technologymetric.idm
JOIN (SELECT idm FROM technologymetric JOIN technology ON technology.id = technologymetric.idt AND technology.name = 'DSA') AS a1
ON a1.idm = technologymetric.idm
JOIN technology ON technology.id=technologymetric.idt
JOIN parametervaluemetric ON parametervaluemetric.idm=metric.id
JOIN parametervalue ON parametervalue.id=parametervaluemetric.idpv
JOIN (SELECT idm, parametervalue.value AS xplotvarvalue FROM parametervaluemetric
JOIN parametervalue ON parametervalue.id=parametervaluemetric.idpv
JOIN parameter ON parameter.id = parametervalue.idp AND parameter.name = 'KeySize' AND parametervalue.value <= 1024)
AS a2 ON a2.idm = parametervaluemetric.idm JOIN parameter ON parameter.id=parametervalue.idp
JOIN metadata ON metadata.id=metric.idm ORDER BY metadata.data, FIELD('parameter.name','KeySize')
EDIT1:结果集行数未定义,通常为1,但取决于&#39; AND parametervalue.value&lt; VALUE&#39 ;.结果集不会影响性能。如果我不使用DISTINCT,则结果集加倍(即:它返回同一行的两倍)。主要的减速与参数的关联,一个是好的,如果我有三个相同的指标,它可能需要3分钟返回一行。我认为罪魁祸首是参数和度量之间的两个多对多表。我们存储的是系统配置(例如数据中心,Web服务器,Android应用程序),它们以焦耳和运行时消耗。
答案 0 :(得分:0)
这种模式可能特别慢:
JOIN ( SELECT ... ) ON ...
JOIN ( SELECT ... ) ON ...
找到制定查询的其他方法。
存在“过度规范化”这样的事情。
考虑使用ENUM
而不是规范化。这将大大提高提供有用索引的能力。
隐藏函数调用中的索引列可防止使用索引。
在您转移其中某些指示后,请提供SHOW CREATE TABLE
和EXPLAIN SELECT
以获得进一步的帮助。
答案 1 :(得分:0)
正如Rick所说,MySQL / MariaDB无法优化在FROM子句中加入的几个子查询(围绕MySQL 5.7进行了一些改进,但还不够)。
因此,我建议通过将相关子查询提取到临时表来修改该模式,这些子查询可以编入索引以便更快地搜索。
在我们开始之前 - 关于索引创建命令的一般说明:有些ALTER语句可能不会按原样运行,因为我不知道字段的类型。在某些情况下,您必须通过让数据库知道列的长度(例如在TEXT列中)来稍微修改它们。
首先,我们将创建索引以确保主查询将尽快运行。这应该只进行一次(希望我没有错过任何东西):
ALTER TABLE `concern` ADD INDEX `concern_idx_name_id` (`name`, `id`);
ALTER TABLE `datatype` ADD INDEX `datatype_idx_name_id` (`name`, `id`);
ALTER TABLE `design` ADD INDEX `design_idx_name_id` (`name`, `id`);
ALTER TABLE `metadata` ADD INDEX `metadata_idx_id_data` (`id`, `data`);
ALTER TABLE `metric` ADD INDEX `metric_idx_idc_idd_iddt_ido_id_idm` (`idc`, `idd`, `iddt`, `ido`, `id`, `idm`);
ALTER TABLE `operation` ADD INDEX `operation_idx_name_id` (`name`, `id`);
ALTER TABLE `parameter` ADD INDEX `parameter_idx_id` (`id`); ALTER TABLE `parametervalue` ADD INDEX `parametervalue_idx_id_idp` (`id`, `idp`);
ALTER TABLE `parametervaluemetric` ADD INDEX `parametervaluemetric_idx_idm_idpv` (`idm`, `idpv`);
ALTER TABLE `technology` ADD INDEX `technology_idx_id` (`id`);
ALTER TABLE `technologymetric` ADD INDEX `technologymetric_idx_idm_idt` (`idm`, `idt`);
ALTER TABLE `technology` ADD INDEX `technology_idx_name_id` (`name`, `id`);
ALTER TABLE `technologymetric` ADD INDEX `technologymetric_idx_idt_idm` (`idt`, `idm`);
ALTER TABLE `technology` ADD INDEX `technology_idx_name_id` (`name`, `id`);
ALTER TABLE `technologymetric` ADD INDEX `technologymetric_idx_idt_idm` (`idt`, `idm`);
ALTER TABLE `parameter` ADD INDEX `parameter_idx_name_id` (`name`, `id`);
ALTER TABLE `parametervalue` ADD INDEX `parametervalue_idx_id_idp_value` (`id`, `idp`, `value`);
ALTER TABLE `parametervaluemetric` ADD INDEX `parametervaluemetric_idx_idpv_idm` (`idpv`, `idm`);
现在出现了应该为每个查询执行完成的部分:
让我们从创建相关的临时表开始:
CREATE TEMPORARY TABLE IF NOT EXISTS temp1 AS SELECT
technologymetric.idm
FROM
technologymetric
JOIN
technology
ON technology.id = technologymetric.idt
AND technology.name = 'AIAK';
CREATE TEMPORARY TABLE IF NOT EXISTS temp2 AS SELECT
technologymetric.idm
FROM
technologymetric
JOIN
technology
ON technology.id = technologymetric.idt
AND technology.name = 'DSA';
CREATE TEMPORARY TABLE IF NOT EXISTS temp3 AS SELECT
parametervaluemetric.idm,
parametervalue.value AS xplotvarvalue
FROM
parametervaluemetric
JOIN
parametervalue
ON parametervalue.id = parametervaluemetric.idpv
JOIN
parameter
ON parameter.id = parametervalue.idp
AND parameter.name = 'KeySize'
AND parametervalue.value <= 1024;
现在让我们为临时表创建索引:
ALTER TABLE `temp1` ADD INDEX `temp1_idx_idm` (`idm`);
ALTER TABLE `temp2` ADD INDEX `temp2_idx_idm` (`idm`);
ALTER TABLE `temp3` ADD INDEX `temp3_idx_idm_xplotvarvalue` (`idm`, `xplotvarvalue`);
现在您可以运行此转换后的主查询:
SELECT
DISTINCT metric.id,
a2.xplotvarvalue,
metric.joules,
metric.seconds,
metadata.data
FROM
metric
JOIN
concern
ON concern.id = metric.idc
AND concern.name = 'Security'
JOIN
design
ON design.id = metric.idd
AND design.name = 'Cryptography'
JOIN
datatype
ON datatype.id = metric.iddt
AND datatype.name = 'String'
JOIN
operation
ON operation.id = metric.ido
AND operation.name = 'KeyGeneration'
JOIN
technologymetric
ON technologymetric.idm = metric.id
JOIN
temp1 AS a0
ON a0.idm = technologymetric.idm
JOIN
temp2 AS a1
ON a1.idm = technologymetric.idm
JOIN
technology
ON technology.id = technologymetric.idt
JOIN
parametervaluemetric
ON parametervaluemetric.idm = metric.id
JOIN
parametervalue
ON parametervalue.id = parametervaluemetric.idpv
JOIN
temp3 AS a2
ON a2.idm = parametervaluemetric.idm
JOIN
parameter
ON parameter.id = parametervalue.idp
JOIN
metadata
ON metadata.id = metric.idm
ORDER BY
metadata.data,
FIELD('parameter.name',
'KeySize')