查询优化:将元数据连接到值列表表

Posted

技术标签:

【中文标题】查询优化:将元数据连接到值列表表【英文标题】:Query optimization: connecting meta data to a value list table 【发布时间】:2017-07-02 08:56:51 【问题描述】:

我有一个包含数据表和元数据表的数据库。我想创建一个视图来选择属于某个项目的某些元数据并将其列为一列。

视图的基本查询是:SELECT * FROM item。项目表定义为:

CREATE TABLE item (
id        INTEGER PRIMARY KEY AUTOINCREMENT
                  UNIQUE
                  NOT NULL,
traceid   INTEGER REFERENCES trace (id) 
                  NOT NULL,
freq      BIGINT  NOT NULL,
value     REAL    NOT NULL
);

要添加的元数据遵循架构“metadata.parameter='name'”

元表定义为:

CREATE TABLE metadata (
id        INTEGER PRIMARY KEY AUTOINCREMENT
                  UNIQUE
                  NOT NULL,
parameter STRING  NOT NULL
                  COLLATE NOCASE,
value     STRING  NOT NULL
                  COLLATE NOCASE,
datasetid INTEGER NOT NULL
                  REFERENCES dataset (id),
traceid   INTEGER REFERENCES trace (id),
itemid    INTEGER REFERENCES item (id) 
);

“name”参数应该这样选择:

如果存在参数为“name”且 itemid 与 item.id 匹配的记录,则其值应包含在记录中。 否则,如果存在参数为“name”、“itemid”为 NULL 且 traceid 与 item.traceid 匹配的记录,则应使用其值 否则,结果应为 NULL,但仍应包含 item 表中的记录

目前,我使用以下查询来实现此目标:

SELECT i.*, 
COALESCE (
  MAX(CASE WHEN m.parameter='name' THEN m.value END), 
  MAX(CASE WHEN m2.parameter='name' THEN m2.value END)
) AS itemname

FROM item i

JOIN metadata m
  ON (m.itemid = i.id AND m.parameter='name')

JOIN metadata m2 
  ON (m2.itemid IS NULL AND m2.traceid = i.traceid AND m2.parameter='name') 

GROUP BY i.id

然而,这个查询有点低效,因为元数据表被使用了两次,并且包含的​​记录比“名称”记录多得多。所以我正在寻找一种提高速度的方法,尤其是在一些扩展即将实现的情况下:

    应该包含第三级“数据集”:如果“参数=名称”与项目具有相同的 datasetid,则应该使用它(将通过搜索另一个连接的项目来查找项目traceid 和 datasetid),如果不存在“参数=名称”且“itemid”匹配或“traceid”匹配

    更多的元数据应该被同一个模式的视图查询

感谢任何帮助。

【问题讨论】:

【参考方案1】:

首先,您可以使用一个连接而不是两个连接,如下所示:

JOIN metadata m ON (m.parameter='name' AND (m.itemId = i.id OR (m.itemId IS NULL AND m.traceid = i.traceid)))

然后你可以删除 COALESCE,使用简单的选择:

SELECT i.*, m.value as itemname

结果应该是这样的:

SELECT i.*, m.value as itemname
FROM item i

JOIN metadata m ON (m.parameter='name' AND (m.itemId = i.id OR (m.itemId IS NULL AND m.traceid = i.traceid)))

GROUP BY i.id

【讨论】:

我已经这么想了,但它不起作用: 1.如果“name”字段存在“metadata.traceid=item.traacid”和“metadata.itemid=NULL” " 和 "metadata.itemid=xxxx (any id)", 选择了错误的元项 2. 它不容易扩展更多列,例如我想要从元字段“源”中附加一个附加列 1.实际上,通过这个查询,itemId = xxxx 和 traceId = xxxx 是不可能的。因为如果仅在 itemId 为空时才考虑 traceId。 2. 我同意这里。这是易于扩展的代码和性能之间的权衡。

以上是关于查询优化:将元数据连接到值列表表的主要内容,如果未能解决你的问题,请参考以下文章

如何将元掩码连接到 dapp?

如何使用 LIMIT syntx 优化具有 17 个连接表的复杂查询并限制每个连接的数据

解决 TypeError:只能将元组(不是“str”)连接到元组

mysql 开发进阶篇系列 23 应用层优化与查询缓存

在 3 个大表上使用内连接优化 SQL 查询

Oracle APEX 5.1使用JDBC和查询数据连接到远程数据库