Rob*_*III 5 performance sql-server optimization
我有一张表,上面有东西的关税;在这种情况下,关税表并不重要,“关税值”很重要。在此演示 SQL Fiddle 中,tariff_plan是tariffplans表的 FK (未包含在示例中)。每个“东西”的关税是tariff_type(出于演示目的简化为一个简单的字符)。
例如,我有一个默认的关税计划(key = default);这是适用于每个客户的资费,除非为该客户定义了另一个值tariff_type。为客户分配了关税计划(plan_x在我的示例中为键 = )。
如果有定义项目的关税a,b,c并且d在默认的计划。在 plan_x 中,我为a和定义了“覆盖”值c。
所以,我做的是我选择default计划(化名p低于p rimary)和左加入“覆盖”计划(plan_x)把它(别名s下面小号econdary):
select *
from tariff_values as p
left outer join tariff_values s
on (p.tariff_type = s.tariff_type) and (s.tariff_plan = 'plan_x')
where (p.tariff_plan = 'default')
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,这导致:
id tariff_plan tariff_type tariff_foo tariff_bar id tariff_plan tariff_type tariff_foo tariff_bar
---- ----------- ----------- ---------- ---------- ---- ----------- ----------- ---------- ----------
1 default a 0.10 0.20 5 plan_x a 0.09 0.19
2 default b 0.55 0.66 NULL NULL NULL NULL NULL
3 default c 1.99 2.99 6 plan_x c 0.99 1.99
4 default d 9.99 6.33 NULL NULL NULL NULL NULL
Run Code Online (Sandbox Code Playgroud)
因为我想把它抽象出来,所以我想把它放到一个表值函数中,这样我就可以创建一个“动态视图”:
select * from dbo.get_tariffplan_for('plan_x', default);
Run Code Online (Sandbox Code Playgroud)
这应该会产生一个类似于表的“虚拟表”(或“动态视图”)tariff_values,因此:没有两个关税 foo 和两个关税栏,让应用程序决定使用哪个。因此,我求助于ISNULL并Case when...构造来“覆盖”默认值:
select p.tariff_type,
ISNULL(s.tariff_foo, p.tariff_foo) as tariff_foo,
ISNULL(s.tariff_bar, p.tariff_bar) as tariff_bar,
ISNULL(s.tariff_plan, p.tariff_plan) as tariff_plan,
CASE WHEN s.id IS NULL THEN 1 ELSE 0 END as isfallback
from tariff_values as p
left outer join tariff_values s
on (p.tariff_type = s.tariff_type) and (s.tariff_plan = 'plan_x')
where (p.tariff_plan = 'default')
Run Code Online (Sandbox Code Playgroud)
这导致:
tariff_type tariff_foo tariff_bar tariff_plan isfallback
----------- ---------- ---------- ----------- -----------
a 0.09 0.19 plan_x 0
b 0.55 0.66 default 1
c 0.99 1.99 plan_x 0
d 9.99 6.33 default 1
Run Code Online (Sandbox Code Playgroud)
我现在需要做的就是将此查询填充到 TVF 中:
CREATE FUNCTION get_tariffplan_for
(
@customerplan as varchar(50),
@defaultplan as varchar(50) = 'default'
)
RETURNS TABLE
AS RETURN
(
select p.tariff_type,
ISNULL(s.tariff_foo, p.tariff_foo) as tariff_foo,
ISNULL(s.tariff_bar, p.tariff_bar) as tariff_bar,
ISNULL(s.tariff_plan, p.tariff_plan) as tariff_plan,
CASE WHEN s.id IS NULL THEN 1 ELSE 0 END as isfallback
from tariff_values as p
left outer join tariff_values s
on (p.tariff_type = s.tariff_type) and (s.tariff_plan = @customerplan)
where (p.tariff_plan = @defaultplan)
);
Run Code Online (Sandbox Code Playgroud)
我们终于得到它了。我们可以按预期调用我们的函数(“动态视图”)(也可以在选择/连接等中使用它)
select * from dbo.get_tariffplan_for('plan_x', default);
--or:
select *
from foo
inner join dbo.get_tariffplan_for('plan_x', default) bar
on foo.tariff_type = bar.tariff_type
Run Code Online (Sandbox Code Playgroud)
现在我的第一个问题是:
我有一种感觉,所有这些ISNULL(或COALESCE)和/或CASE WHEN ...特技似乎不必要地使事情复杂化,并且有些东西告诉我这可以更有效地完成。但是,我想不出更好和/或更有效的替代方案。
所以我希望这里有人对如何改进这一点有一些想法。
我的第二个问题是:
如果我有一个专门卖给某个客户的产品(q例如,tariff_type )怎么办?关税不会在默认关税计划中,所以我必须在上面添加另一个(使用工会)才能在结果集中获得该客户的所有独家关税。这将导致这样的查询: select
select p.tariff_type,
ISNULL(s.tariff_foo, p.tariff_foo) as tariff_foo,
ISNULL(s.tariff_bar, p.tariff_bar) as tariff_bar,
ISNULL(s.tariff_plan, p.tariff_plan) as tariff_plan,
CASE WHEN s.id IS NULL THEN 1 ELSE 0 END as isfallback,
0 as isexclusive
from tariff_values as p
left outer join tariff_values s
on (p.tariff_type = s.tariff_type) and (s.tariff_plan = @customerplan)
where (p.tariff_plan = @defaultplan)
UNION
--Exclusive values
select p.tariff_type,
p.tariff_foo,
p.tariff_bar,
p.tariff_plan,
0 as isfallback,
1 as isexclusive
from tariff_values p
left outer join tariff_values s
on (p.tariff_type = s.tariff_type) AND (s.tariff_plan = 'default')
where p.tariff_plan = 'plan_x'
and s.id is null
Run Code Online (Sandbox Code Playgroud)
(在此 SQL 小提琴中演示)
在上面的示例中,我使用另一个left joinwith s.id is null(但可以以其他方式重写(使用count, exists, not in, having...无论如何))来检索客户专属关税。但也许有更好的方法来代替工会?
有几个问题,因为我的代表太低,无法通过评论发布
您想对输出做什么?您可以在多大程度上更改数据模型?
如果表布局和输出都必须与您的示例中完全相同,那么我看不到任何重大改进。外连接+ isnull 还不错。
为了提高性能,您可以:
如果更改 DDL 或数据可以,您还可以:
关于最后一个要求,我猜这意味着可能有不存在默认情况的关税计划?完整的外部连接也应该有效。
我猜你正在使用 TVF 来避免将其置于正常视图中的麻烦?我有一种感觉,应该可以使用普通视图而不会造成性能损失,尽管查询会变得更加复杂。
这是一个建议:
CREATE FUNCTION get_tariffplan_for
(
@customerplan as varchar(50)
)
RETURNS TABLE
AS RETURN
(
select p.tariff_type,
ISNULL(s.tariff_foo, p.tariff_foo) as tariff_foo,
ISNULL(s.tariff_bar, p.tariff_bar) as tariff_bar,
ISNULL(s.tariff_plan, p.tariff_plan) as tariff_plan,
CASE WHEN s.id IS NULL THEN 1 ELSE 0 END as isfallback
from default_tariff_values as p
full outer join specific_tariff_values s
on (p.tariff_type = s.tariff_type) and (s.tariff_plan = @customerplan)
);
Run Code Online (Sandbox Code Playgroud)
编辑:这是一个提案(不改变数据模型)
CREATE FUNCTION get_tariffplan_for
(
@customerplan as varchar(50)
)
RETURNS TABLE
AS RETURN
(
select p.tariff_type,
ISNULL(s.tariff_foo, p.tariff_foo) as tariff_foo,
ISNULL(s.tariff_bar, p.tariff_bar) as tariff_bar,
ISNULL(s.tariff_plan, p.tariff_plan) as tariff_plan,
CASE WHEN s.id IS NULL THEN 1 ELSE 0 END as isfallback,
CASE WHEN p.id IS NULL then 1 else 0 END as isexclusive
from
(select tariff_type,tariff_foo,tariff_bar,tariff_plan
from tariff_values where tariff_plan = 'default')
as p
full outer join
(select tariff_type,tariff_foo,tariff_bar,tariff_plan
from tariff_values where tariff_plan = @customerplan)
as s
on (p.tariff_type = s.tariff_type)
);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
492 次 |
| 最近记录: |