数据库中的统计查询和组合查询
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据库中的统计查询和组合查询相关的知识,希望对你有一定的参考价值。
有这样3个表,分别是
药品(编号,名称,价格,厂商)
处方(药品编号,数量,医生编号)
医生 (编号,姓名,科室,职称)
要求统计每个科室“青霉素”用量,只能用单表查询里面的聚合函数和组合查询解决,不能用连接查询。请问这个问题有解决的方法吗?怎么写查询代码?
select 科室,sum(数量)
from 医生,处方,药品
where 药品.名称='青霉素'
and 医生.编号 = 处方.医生编号
and 处方.药品编号 = 药品.编号
group by 科室
你要求不连接单表
declare @药编号 int
select @药编号=编号 from 药品 where 名称='青霉素'
select 科室,
sum((select 数量 from 处方 where 医生编号=医生.编号 and 药品编号=@药编号))
from 医生
group by 科室 参考技术A select 科室,sum(数量) from (select 科室,(select sum(数量) from 处方 where 药品编号 in (select 编号 from 药品 where 名称='青霉素') and 医生编号=a.编号 ) as 数量 from 医生 a) b group by 科室本回答被提问者采纳 参考技术B 针对你的问题数据库实验:统计查询和组合查询,
提供一份的适用于初学者的代码对你来说是有必要的,
还有别的要求么,可以与我们联系,
告诉我你的问题和email,
有时间可以帮你,肯定救急,
使用百度_hi给我留言,
此回复针对所有来访者和需求者有效,
es:\\3a1085fd181aeda1c3bfab175e7fb378
通过手动创建统计信息优化sql查询性能案例
本质原因在于:SQL Server 统计信息只包含复合索引的第一个列的信息,而不包含复合索引数据组合的信息
来源于工作中的一个实际问题,
这里是组合列数据不均匀导致查询无法预估数据行数,从而导致无法选择合理的执行计划导致性能低下的情况
我这里把问题简单化,主要是为了说明问题
如下一张业务表,主要看两个“状态”字段,BusinessStatus1 和 BusinessStatus2
create table BusinessTable
(
Id int identity(1,1),
Col2 varchar(50),
Col3 varchar(50),
Col4 varchar(50),
BusinessStatus1 tinyint,
BusinessStatus2 tinyint,
CreateDate Datetime
)
GO
--向测试表中写入数据:
begin tran
declare @i int
set @i=0
while @i<500000
begin
insert into BusinessTable values (NEWID(),NEWID(),NEWID(),1,10,GETDATE()-RAND()*1000)
insert into BusinessTable values (NEWID(),NEWID(),NEWID(),1,20,GETDATE()-RAND()*1000)
insert into BusinessTable values (NEWID(),NEWID(),NEWID(),1,30,GETDATE()-RAND()*1000)
insert into BusinessTable values (NEWID(),NEWID(),NEWID(),2,20,GETDATE()-RAND()*1000)
insert into BusinessTable values (NEWID(),NEWID(),NEWID(),2,30,GETDATE()-RAND()*1000)
insert into BusinessTable values (NEWID(),NEWID(),NEWID(),2,40,GETDATE()-RAND()*1000)
insert into BusinessTable values (NEWID(),NEWID(),NEWID(),3,30,GETDATE()-RAND()*1000)
insert into BusinessTable values (NEWID(),NEWID(),NEWID(),3,40,GETDATE()-RAND()*1000)
insert into BusinessTable values (NEWID(),NEWID(),NEWID(),3,50,GETDATE()-RAND()*1000)
set @i=@i+1
end
commit
--插入一条特殊数据,也就是实际业务场景中:
insert into BusinessTable values (NEWID(),NEWID(),NEWID(),3,10,GETDATE()-RAND()*1000)
--测试数据的特点是:
--BusinessStatus1 的分布位:1,2,3,
--BusinessStatus2 的分布位:10,20,30,40,50
--目前数据的对应关系,
--但是注意插入的一条特殊数据:
--BusinessStatus1 和 BusinessStatus2 的组合为:BusinessStatus1=3 and BusinessStatus2=10,在451W条数据中是唯一的一个组合
--创建如下索引:
Create Clustered index idx_createDate on BusinessTable(CreateDate)
Create Index idx_status on BusinessTable(BusinessStatus1,BusinessStatus2)
进行如下查询,就是查询那条所谓的特殊数据
1
2
3
|
select * from BusinessTable where BusinessStatus1=3 and BusinessStatus2=10 |
发现执行计划如下:走的是全表扫描,IO代价也不小,
这种情况下,明明只有一条数据,却要走全表扫描
(实际业务中类似数据也不仅只有一条这么巧,但是在千万级的表中,符合类似条件的数据很少,
打个比方好理解一点,就像订单表一样,订单是退订状态,且尚未退款,这种数据的分布是少之又少吧
只是举例,不要较真)
上面查询的IO信息
再通过强制索引提示的情况下,发现同样的查询,IO有一个非常大的下降
分析上述sql为什么不走索引?因为毕竟符合条件的数据只有一条,走全表扫描代价也过于大了,尤其是实际情况中,业务表更大,逻辑也没有这么直白
这个还要从索引统计信息说起,在符合索引中,索引统计信息只是统计前导列的,对于组合列的分布,sqlserver是无法预估到的,这一点可以通过第一个查询的执行计划发现
sqlserver只是能够预估到 BusinessStatus1 =3 的情况下的数据分布,但是无法预估到 BusinessStatus1=3 and BusinessStatus2=10这个组合情况下的数据分布情况
当然通过统计信息也可以看到,统计信息只记录了BusinessStatus1的列的数据分布情况,但是实际执行的过程中,无法预估BusinessStatus1=3 and BusinessStatus2=10的准确分布
找到了问题的原因,就容易解决了,既然sqlserver无法预估到BusinessStatus1=3 and BusinessStatus2=10这个组合条件的数据分布请,
那么就创建一个过滤统计信息,让sqlserver准确地知道这个条件下数据的分布请,就容易做出相对准确的执行计划了
通过如下语句,创建一个该条件的统计信息
create statistics BusinessTableFilterStatistics
on BusinessTable(BusinessStatus1,BusinessStatus2)
where BusinessStatus1=3 and BusinessStatus2=10
--创建完统计信息之后注意要做个更新
UPDATE STATISTICS BusinessTable BusinessTableFilterStatistics with fullscan
创建完统计信息之后,发现表上会增加一个刚刚创建的统计信息
现在再来看这个查询的执行计划情况,发现其按照预期的走了索引
同时观察起IO情况,也有一个大幅度的下降
总结:
以上通过手动创建统计信息,来促使sqlserver在生成执行计划的时候,准确地知道数据的分布情况,做出较为优化的执行计划,在某些特殊的情况下,可以作为优化的一个考虑方向
后记:
或许有人认为这个问题该归结于parameter sniff的问题,其实这个问题跟parameter sniff还不太一样(当然也有一点像)
通常情况下,所说的parameter sniff问题是单列数据分布不均匀的情况下,因为执行计划重用导致性能地下的一个现象,重点是执行计划的不合理重用
这里的问题在于,由于统计信息的数据计算方式,sqlserver 压根无法预估到符合条件数据的准确分布,从而无法做出合理的执行计划的情况
当然这种情况也比较特殊,在强制索引提示以外,可以通过手动创建统计信息来达到优化的目的
以上是关于数据库中的统计查询和组合查询的主要内容,如果未能解决你的问题,请参考以下文章