我收到了一个我不确定如何设计的表格。我希望有一些设计建议或正确方向的指点。该表称为edge
,用于存储一些事件跟踪以及链接到许多possible查找表的ID。除去ID以外的所有内容,这是表中包含的所有UUID:
ID
InvID
OrgID
FacilityID
FromAssemblyID
FromAssociatedTo
FromAssociatedToID
FromClinicID
FromFacilityDepartmentID
FromFacilityID
FromFacilityLocationID
FromScanAtFacilityID
FromScanID
FromSCaseID
FromSterilizerLoadID
FromWasherLoadID
FromWebUserID
ToAssemblyID
ToAssociatedTo
ToAssociatedToID
ToClinicID
ToFacilityDepartmentID
ToFacilityID
ToFacilityLocationID
ToNodeDTS
ToScanAtFacilityID
ToScanID
ToSCaseID
ToSterilizerLoadID
ToUserName
ToWasherLoadID
ToWebUserID
这是可能要加入的大量ID。我记得读过一篇文章,当您有十几个以上的加入时,Postgres规划器就放弃了。想法是要探索的排列太多,以至于计划时间可能很快使查询时间不堪重负。如果将其简化,那么“ from”和“ to”链接将在所有这些字段中仅具有一个关键值。因此,实现为多态/混杂关系,如下所示:
ID
InvID
OrgID
FacilityID
FromID
FromType
ToID
ToType
ToWebUserID
此表将是巨大的,因此/将要考虑速度。
我鼓励作者not使用多态设计,尽管吸引力很明显。 (我喜欢Karwin的SQL Antipatterns书。)但是现在,面对近三打ID,我有些困惑。
是否有解决此类问题的通用解决方案?也就是说,您在哪里拥有这样的中央表,并可以连接到各种可能的表?我没有数据仓库背景,但是看起来有点像那样。 (此表的作者已阅读Kimball的书,但也未执行任何数据仓库实现。)
重要:我们正在使用JOIN
对可能更改的相关值进行查找,我们正在[[not使用它来更改结果集的大小。只是假装它永远是LEFT JOIN
。
From
和To
ID的联接,而是使用自定义函数调用从相关表中查找所需的值。像(伪代码)GetUserName(uuid) : citext
...and os on for other values of interest in this and other tables...
当UUID为0000等时,该函数将返回''。我很高兴这不是SO历史上最棘手的问题,我希望能有一个朝着富有成果的方向发展的指针。
我在此类问题中遵循的一条经验法则是对事物进行建模,以使您的查询变得简单自然。经验表明,这通常会带来良好的效果。
我假设您显示的表是星型架构的事实表,并且外键指向许多维表,因此您的查询看起来像]
SELECT ...
FROM fact
JOIN dim1 ON fact.dim1_id = dim1.id
JOIN dim2 ON fact.dim3_id = dim2.id
JOIN dim3 ON fact.dim3_id = dim3.id
...
WHERE dim1.col1 = ...
AND dim2.col2 BETWEEN ... AND ...
AND dim3.col3 < ...
...
现在,PostgreSQL默认情况下仅考虑前八个表(join_collapse_limit
)的所有联接排列,而其余表仅按照它们在查询中出现的顺序联接。此外,如果表的数量达到12(
geqo_threshold
)的阈值,遗传查询优化器将接管,该组件通过随机选择的执行计划来模拟通过优胜劣汰的变异和生存来模拟进化!),因此并非总是针对相同的查询提出相同的执行计划。
因此,我的建议是以如下方式编写查询:前七个维表是最有可能最大程度地减少结果行数的表(基于WHERE
条件)。您还可以增加join_collapse_limit
,因为如果您的查询仍然要花很长时间运行,那么您可以轻松地使计划者花费更多的时间来考虑最佳计划。然后您将
geqo = off
设置为禁用遗传查询优化器。如果您根据这些原则设计查询,则应该能够获得良好的执行计划,而不会弄乱数据模型。