MariaDB确实减缓了关于联接联接的查询

时间:2018-02-05 13:20:12

标签: mysql performance join mariadb query-performance

我附加了数据库的Schema。 enter image description here 当表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应用程序),它们以焦耳和运行时消耗。

2 个答案:

答案 0 :(得分:0)

这种模式可能特别慢:

JOIN ( SELECT ... ) ON ...
JOIN ( SELECT ... ) ON ...

找到制定查询的其他方法。

存在“过度规范化”这样的事情。

考虑使用ENUM而不是规范化。这将大大提高提供有用索引的能力。

“Key-value”,即EAV,架构是有问题的。重新思考你是否真的需要它。如果您必须保留EAV,请按照提示here进行操作。更多关于EAV

隐藏函数调用中的索引列可防止使用索引。

在您转移其中某些指示后,请提供SHOW CREATE TABLEEXPLAIN 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`);

现在出现了应该为每个查询执行完成的部分:

  1. 创建临时表。
  2. 为临时表创建索引。
  3. 运行主查询。
  4. 让我们从创建相关的临时表开始:

    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')