我不是SQL专家,请帮忙,我该如何优化此查询?
我没有索引,只有名为master_table的表和更多表,我必须优化此查询才能获得相同的结果,如果必须,我可以创建索引,但我无法更改创建表....
select month(date_hour), passenger, nationality, passport, airline,
count(*) N_Viagens
from masterTable
group by month(date_hour), passenger, airline, nationality, passport
having count(*) > 10
接下来是创建表的代码,但我无法编辑该代码,只能编辑查询或创建索引:
select
p.birthdate, p.gender, p.passport, p.name + ' ' + p.surname passenger, p.nationality,
r.class, r.flightNR, r.payment, r.ticketNR,
f.src_AP_ID, f.dest_AP_ID, f.AL_ID, f.date_hour, f.AirCrft_Code,ac.manufacturer, ac.model,
SA.City 'Origin City', SA.Country 'Origin Country', SA.Name 'Origin Airport',
DA.City 'Dest City', DA.Country 'Dest Country', DA.Name 'Dest Airport',
al.Name airline, al.IATA, al.icao
into masterTable
from passenger p
join reservation r on r.passport = p.passport
join flight f on f.flightNR = r.flightNR
join airport SA on f.src_AP_ID = SA.AP_Id
join airport DA on f.dest_AP_ID = DA.AP_Id
join aircraft ac on f.airCrft_Code = ac.code
join airline al on f.AL_ID = al.AL_ID
没有索引:
SQL Server Execution Times: CPU time = 10125 ms, elapsed time = 17052 ms.
我认为我知道了,感谢所有人,再次感谢
我创建了这样的索引:
create index idx_MasterTable_Passenger on masterTable(passport, airline)
并且查询我改为:
select month(date_hour), max(passenger) as passenger, nationality, passport, airline, count(*) N_Viagens
from masterTable
group by airline, nationality, passport, month(date_hour)
having count(*) > 10
您的想法,是否可以接受?
SQL Server Execution Times: CPU time = 8362 ms, elapsed time = 5721 ms.
如果他同意这个话,我会和老师谈谈
老师没有接受这个更改,我们无法更改表或查询,只能创建一个好的索引....建议??
答案 0 :(得分:1)
这是一个棘手的问题 - 为了真正加快month(date_hour)
上的分组,你需要一个功能索引(在MS SQL Server中称为index on a computed column)确切的表达。仅仅在date_hour
上设置索引是不够的。
在this example中,第二个表有一个计算列和一个索引(而第一个表没有)。请注意,相同的查询具有不同的执行计划,其中第一个实际排序数据,第二个查询只是通过索引。
由于这是一个家庭作业,我会让你自己将这个纳入你的例子。
顺便说一下,如果您对索引和性能主题感兴趣,我热烈推荐阅读:Use The Index, Luke!
答案 1 :(得分:0)
MasterTable包含什么?看起来它会包含像乘客的航段一样的东西。如果是这样,很少有乘客每月飞行10次以上。
您可以通过执行以下操作来提高性能:
(1)在万事达中建立乘客指数:
create index idx_MasterTable_Passenger on MasterTable(Passenger);
(2)认识到飞行10次的人相对于其他人来说是罕见的,所以过滤掉它们:
select month(date_hour), passenger, nationality, passport, airline,
count(*) as N_Viagens
from masterTable
where passenger in (select passenger from MasterTable group by passenger having count(*) >= 10)
group by month(date_hour), passenger, airline, nationality, passport
having count(*) > 10
这可能会加快查询速度。
但是,我会建议一些不同的东西。创建一个表格,按乘客(或某些类似的级别)汇总信息,以回答此类问题。将新数据添加到主表时,请将行更新或插入此表。
例如,您可能需要一个结构为,,的摘要表。在晚上或每周一次运行此查询,它可能会回答很多问题。
答案 2 :(得分:0)
此查询始终需要扫描。现在有WHERE子句,因此我们无法通过快速隔离较小的子集来加速查询。有一个HAVING子句但它只能在聚合后应用。
但是有一个GROUP BY子句;可以通过添加适当的索引来加速GROUP BY子句上的聚合。因为GROUP BY子句中的列也在SELECT列表中使用,所以我们可以实现只需要扫描该索引,而不是整个表。
GROUP BY子句包含表达式month(date_hour)。这意味着我们可以忽略这个指数。仍然是乘客,航空公司,国籍,护照。在创建索引之前,您必须确定正确的顺序。我的预感是你需要首先放置最具选择性的列 - 也就是说,具有最多唯一值的列应该出现在具有少量唯一值的列之前。我猜这个订单乘客,航空公司,国籍,护照已经相当不错了。那说我会通过改变列的顺序来尝试一点。
创建索引后,您不必重写查询。但是,如果您的RDBMS的优化器是天真的(如MySQL),则必须将month(date_hour)表达式作为GROUP BY子句的最后一个表达式。这不会以任何方式更改结果,尽管它可能会影响返回行的顺序。然而,这根本不重要(如果确实如此,你应该添加一个ORDER BY子句)
答案 3 :(得分:0)
出现护照是比名称更好的标识符。允许许多人改名的事实。
在护照,航空公司
上创建索引你可以将指数扩展到国籍,护照,航空公司,乘客,但不确定你买多少钱?
select nationality, passport, airline, year(date_hour), month(date_hour), max(passenger), count(*) N_Viagens
from masterTable
group by nationality, passport, airline, year(date_hour), month(date_hour)
having count(*) > 10