优化特定的sql查询

时间:2012-05-29 18:29:50

标签: sql sql-server sql-server-2008 tsql

我不是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.

如果他同意这个话,我会和老师谈谈

老师没有接受这个更改,我们无法更改表或查询,只能创建一个好的索引....建议??

4 个答案:

答案 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