【问题标题】:Performance of MySQL query with dynamic field insertion具有动态字段插入的 MySQL 查询性能
【发布时间】:2015-09-11 12:29:03
【问题描述】:

我们的数据是机密的,因此我在这里创建虚拟数据。记录数为 100 000。

Table1 表格:

+------------------+
| formID  formName |
+------------------+
|   1     student  |
|   2     teacher  |
+------------------+

Table2 字段:

+--------------------+
| fieldID  fieldName |
+--------------------+
|   1      Name      |
|   2      Location  |
+--------------------+

Table3 表单域:

+----------------------------+
|   formID fieldID Value     |
+----------------------------+
|   1      1     studentName |
|   1      2     ahmedabad   |
|   2      1     teacherName |
|   2      2     mumbai      |
+----------------------------+

我的查询:

select frm.formName, 
(
    select frmfld.Value from FormField frmfld 
    WHERE frmfld.fieldID = 1 AND frmfld.formID = frm.formID
) AS Name,
(
    select frmfld.Value from FormField frmfld 
    WHERE frmfld.fieldID = 2 AND frmfld.formID = frm.formID
) AS Location 
From Form frm

在这里,字段可能会动态增加,对于该字段,我们每次都在使用代码库创建查询时附加新的子查询部分。随着此字段增长到 100,此查询的执行时间由于子查询而增长到 7 到 8 分钟,这是不可接受的。

【问题讨论】:

  • 提供EXPLAIN的输出,提供你的MySQL配置变量,提供你的服务器硬件信息。您正在使用 EAV 结构,并且根据您所做的判断 - 它很可能设计得更好。另外,什么是 1lac?我从来没有见过,你有没有机会把它转换成公制单位?
  • 你不需要那些子查询。简单的JOINs 就可以了。
  • 我不能分享解释的输出,因为它是机密的,我上面分享的内容是假的。如果您对这种结构有更好的设计,那么欢迎您的建议。 @Mjh:1 lac 表示 100k。
  • @HannoBinder :简单的连接在这里没有用,因为我需要将数据从行转换为列。
  • 您发布的查询只能使用JOINs 完全复制。您还有其他没有提到的要求吗?

标签: java mysql


【解决方案1】:

我的要求是支持无限的动态字段

这行不通。固定数量的字段是完全可行的,虽然性能会随着每个添加字段而降低,但一个未知的动态数字很难处理。

SELECT frm.formName, 
       frmfld1.Value AS Name,
       frmfld2.Value AS Location 
FROM Form frm
LEFT OUTER JOIN FormField frmfld1 ON frmfld1.formID = frm.formID AND frmfld1.fieldID = 1
LEFT OUTER JOIN FormField frmfld2 ON frmfld2.formID = frm.formID AND frmfld2.fieldID = 2

确保您在 Form(formID)FormField(formID, fieldID) 上有索引。

【讨论】:

  • 我已经用 30 个动态字段和 100k 条记录测试了这种方法,性能略有提高。以前需要 37 秒,现在需要 32 秒。我应该使用哪些其他方法来进一步改进?
  • 如果你已经有了合适的索引,我认为没有什么可以做的了。如果您可以限制结果候选人,那应该会有所帮助。比如WHERE frm.formID BETWEEN 123 AND 234
  • 通常,我会说,您让 GUI/客户端处理将(动态)行重新格式化为列,因为 rel DB 和 SQL 不是为此而设计的。
【解决方案2】:

您对数据库进行规范化的次数越多,获取成本就越高。这意味着您需要加入更多表格。所以在这里你有同样的问题。

我建议改用视图,这将在一定程度上帮助您。但这不是长期的解决方案。另一个选项是如果您可以为索引列提供“位置”条件。这真的很有帮助。

【讨论】:

    【解决方案3】:

    http://sqlfiddle.com/#!9/013eb2/3

    SELECT frm.formName, 
      GROUP_CONCAT(IF(frmfld.fieldID=1,frmfld.Value,NULL)) AS Name,
      GROUP_CONCAT(IF(frmfld.fieldID=2,frmfld.Value,NULL)) AS Location
    FROM Form frm
    LEFT JOIN FormField frmfld
    ON frmfld.formID = frm.formID
    GROUP BY frm.formID
    

    【讨论】:

      猜你喜欢
      • 2020-01-30
      • 2015-04-10
      • 2018-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多