使用存储过程作为“动态”视图?

时间:2009-04-22 01:14:23

标签: sql postgresql

我想创建一个“视图”,以便在我正在处理的应用中从大约90个查询中删除相同的三行子查询。

问题是子查询包含基于变量的条件。

SELECT * FROM items WHERE id NOT IN (
  SELECT item_id FROM excluded_items WHERE user_id = 123
);

如果它不是变量,我可以简单地制作一个视图并完成它。

我不知道在这种情况下该怎么做。在视图背后采用相同的心态我很想制作一个返回所需记录集的存储过程,以便可以这样调用:

SELECT * FROM user_items(123);

现在我有一个地方可以更新此项目排除和任何其他条件,但是如果我想将该SP的结果与其他表格相结合,我不确定索引是如何受到影响的?

这是好/坏的做法吗?有没有其他方法可以做到,或者我应该把它搞砸并继续复制这个子查询?

4 个答案:

答案 0 :(得分:3)

像往常一样您的里程可能会有所不同。如果您担心这在代码语法方面是一个很好的做法,我认为这不重要。使用存储过程返回记录集是非常正常的,如果它可以节省您的开发时间 - 那么为什么不这样做呢?但是,如果您确定查询执行时间的成本受到如此负面影响,以至于您的业务成本高于程序员的生产力,那么无论如何都不要使用存储过程。

多年来,我听到很多关于人们称其为邪恶的最佳实践的存储过程的玩笑。我得出的结论是一如既往地使用正确的工具。

要确定更改如何影响性能,请使用以下命令执行一些测试查询:

EXPLAIN ANALYZE SELECT * FROM items WHERE id NOT IN (
  SELECT item_id FROM excluded_items WHERE user_id = 123
);

然后

EXPLAIN ANALYZE SELECT * FROM user_items(123);

然后比较执行时间和查询计划。我想你将能够做出更明智的决定。

答案 1 :(得分:2)

你有没有试过像

这样的东西
create view user_items as (
  select i.*, u.id as user_id
    from (items i cross join users u)
      left join excluded_items e
      on (i.id = e.item_id
        and u.id = e.user_id)
    where e.item_id is null
);

已经?我使用PostgreSQL 8.3测试它,如果你在简单的查询中使用视图,它可以将user_id上的条件拉入交叉连接中,如

select *
  from user_items ui
  where user_id = 1;

如果使用此视图的查询变得过于复杂,以至于查询优化器无法将user_id上的条件拉入交叉连接并计算完整的交叉连接,那么您仍然可以使用某些parameters查询优化器再次将其拉入。

答案 2 :(得分:1)

我认为存储过程解决方案更干,并且确实提高了可读性。虽然我当然更喜欢在可能的情况下使用视图(特别是使用PostgreSQL强大的规则),但我想不出更好的表达方式。

答案 3 :(得分:-2)

在90个地方拥有相同的SQL也可以在客户端解决。例如,创建一个构建SQL字符串的函数:

public string SqlItemsForUser(int iUserId) {
    return "SELECT * FROM items WHERE id NOT IN ( " +
        "SELECT item_id FROM excluded_items WHERE user_id = " +
        Convert.ToString(iUserId) + ");";
}

您可以在90个地方调用此函数,因此如果您需要更改子查询,则只需在一个位置更改它。