复杂查询的查看或存储过程?

时间:2011-10-20 14:08:54

标签: mysql performance database-design stored-procedures sql-view

我有一个带有多个(嵌套)子查询的复杂查询,我希望这些子查询可供应用程序开发人员使用。该查询是通用的,并且在数据集的集合上生成具有计算值的视图,并且开发者预期仅需要来自查询返回的一些记录(即,它们将限制某个实体的ID或日期范围的结果或某些这样)。

我可以看到实现这个的3种方法:

  1. 让开发人员将查询嵌入到每个应用程序中,并根据需要添加自己的WHERE子句。
  2. 创建一个存储过程,接受我希望开发人员需要的所有条件作为参数(为了让参数可以说我可以预测在可预见的未来需要什么),并且该过程将运行复杂查询并根据传递的参数对其进行过滤。
  3. 将查询实现为具有多个子视图的视图(因为MySQL不允许在视图中进行子查询)并让开发人员将其用作表并使用WHERE让每个应用程序应用过滤器需要。目前我正在寻找3个额外的子视图,主要是因为一些子查询被多次使用并且作为子视图执行它们可以防止重复 - 否则它可能会更糟; - )。
  4. 明智的表现会更好吗? (假设所有索引在所有情况下都是等效的)如果可能的话,去最坏的情况。

    您认为代码维护术语会更好吗?

2 个答案:

答案 0 :(得分:7)

我喜欢定义“好”的问题 - 你特别询问了性能和可维护性,这可以让我们回答谈论这种权衡。

从性能的角度来看,我不认为3个选项之间可能存在任何差异,只要查询和数据符合您的预期方案即可。我测试了100倍以上的数据,并可能扩大“where”子句以查看发生了什么,但索引结构等更有可能影响性能,而不是从存储过程执行相同的SQL,通过查看或从客户端应用程序。

回答这个问题的最好方法就是测试它 - 当然,有许多具体的细节可能会使我们的溢出者可以给出的一般“我期望的x,y或z”答案无效。如果性能是一个关键问题,请使用数据库填充工具(Redgate make on,我过去使用过DBMonster)并尝试所有3个选项。

从维护点来看,我提供了一个选项4,在我看来,这是迄今为止最好的选项。

选项4:构建一个数据访问库,封装对数据的访问。让库公开方法和参数以优化记录选择。考虑使用规范模式(http://en.wikipedia.org/wiki/Specification_pattern)。使用库中最好的查询,不要打扰开发人员的实现细节。

如果这不起作用 - 异构应用程序代码,对简单需求的更改太多 - 我会按如下方式评估选项:

  1. 嵌入式SQL:根据重新使用此SQL的次数,这可能没问题。如果只有一部分代码运行SQL,那么它在逻辑上类似于数据访问库。但是,如果相同的代码片段需要在很多地方重复使用,那么它可能是错误的来源 - SQL中的一个小变化需要在几个地方重复。

  2. 存储过程:出于维护原因,我通常不喜欢存储过程 - 它们容易因过载而变脆,并创建一种程序化的思维方式。例如,如果您在单独的存储过程中有其他要求使用此SQL计算,则很快就会得到一个过程编程模型,存储过程会相互调用。

  3. 观点:这可能是最好的选择。它将特定的数据逻辑放在一个地方,但促进了基于集合的逻辑的使用,因为访问路由是通过SELECT语句,而不是通过执行过程语句。视图很容易合并到其他查询中。

答案 1 :(得分:3)

如果实施得当,三种解决方案中的任何一种都可以用于管理,但请记住在迁移过程中如何处理每种解决方案(代码或数据库迁移)。

如果查询很大,由于带宽开销较小,存储过程会给你一些额外的性能,因为它发送的是较小的查询。您也可以通过此解决方案获得额外的安全性。

对于 manteinance 解决方案,我更喜欢第一个和第二个解决方案,因为您可以对查询进行任何更改,而无需进行任何数据库更改。如果你选择第一个解决方案,我会在一个函数中包装查询调用,这样你就只有一个地方可以进行更改。

开发人员的角度来看,我会选择视图解决方案beacuse是最透明的,我的意思就像查询常规表一样,你可以使用describe命令检查表结构,或者只是选择您需要查询的字段和条件,或者加入另一个表等...

关于 where子句灵活性,您可以使用任何建议的解决方案来实现它。你可以在包装函数(1)中添加where参数,你可以在存储过程中添加where参数但是要注意注入(2),或者开发人员可以像往常一样在视图中添加where子句(3)< / p>

请记住,在MySQL视图中不是临时表,如果查询非常复杂如果查询被大量使用并以不同方式使用,则此解决方案将不是最好的(禁用缓存性能提升)。 我会考虑一个临时表解决方案(计数器表),它使用编程的任务/ cron更新每个时间段(例如一天,一周,每当需要时)或通过设置propper触发器来更新。这个解决方案可以提高性能。

希望这有所帮助,我最喜欢视图解决方案,但从数据库的角度来看,它可能更复杂。