我已经承担了许多存储过程的责任,这些过程采用以下形式:
create procedure getFoos()
begin
set @v_sql := '';
set @v_sql := concat(@v_sql, 'select distinct ', getFooFields('f', 'b'), ' ');
set @v_sql := concat(@v_sql, 'from Foos f ');
set @v_sql := concat(@v_sql, ' left join Bars b on f.barID= b.barID');
set @v_sql := concat(@v_sql, 'where f.someDate is null ');
set @v_sql := concat(@v_sql, ' and b.someID in (1, 2, 3) ');
set @v_sql := concat(@v_sql, ' and b.someBool = true ');
set @v_sql := concat(@v_sql, 'order by f.name ');
prepare s1 from @v_sql;
execute s1;
deallocate prepare s1;
end;
如您所见,正在使用动态SQL,以便可以内联函数getFooFields
。该函数仅用于构建所选字段的字符串:
create function getFooFields(
i_aliasForFoo varchar(32),
i_aliasForBar varchar(32)
) returns text
reads sql data
begin
declare v_fields text default '';
set v_fields := concat(v_fields, i_aliasForFoo, '.fooID as fooId', ', ');
set v_fields := concat(v_fields, i_aliasForFoo, '.someDate as someDate ', ', ');
set v_fields := concat(v_fields, i_aliasForFoo, '.name as name', ', ');
-- additional Foo fields
set v_fields := concat(v_fields, i_aliasForBar, '.someID as someID ', ', ');
set v_fields := concat(v_fields, i_aliasForBar, '.someBool as someBool ', ', ');
-- additional Bar fields
return v_fields;
end;
这样做的原因似乎是更好的可维护性 - 当Foos
或Bars
表被更改时,只需要在一个函数中进行更改,而不是在许多过程中进行更改。然而,这是以使用动态SQL为代价的,以及每次调用它时构建相同字符串的额外函数。我想知道在运行之前是否有办法保持可维护性。
实际上,我们在Eclipse中管理我们的SQL并使用Ant来按摩这些文件,然后在每次部署之前在数据库上运行它们。有没有办法让Ant编写脚本以完成getFooFields
的工作?我想象如下:
select distinct <%foofields%> from Foos
...
Ant将使用与<%foofields%>
正在构建的字符串类似的字符串替换getFooFields
。但当然,getFooFields
采用参数这一事实使得这一点更加复杂,因此我不确定它是如何工作的。
这个想法完全被误导了吗?我几乎没有任何使用Ant的经验,所以我无法分辨。或者,我可以通过其他方式删除这些过程对动态SQL的依赖,同时保持它们的可维护性吗?
答案 0 :(得分:1)
如果getFooFields
最常用于选择表foo
中的所有字段,那么最好使用select * from foo
而不是动态SQL和函数的组合。
如果它是foo
中经常作为一个组出现的字段的子集,那么通过将该子集创建为视图并查询该视图可能会更好。
如果getFooFields
从另一个应用程序中选择字段列表以从foo
中进行选择,那么您必须检查这是否有意义。 foo
中有多少个字段?您多久只需要少数这些领域?你是否为这种“优化”提取了足够多的记录才有意义?最有可能的是,你不是,只是拉动公共领域或所有领域会更好。