1

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

4 回答 4

1

这是一个棘手的问题 - 要真正加快对 的分组month(date_hour),您需要在该精确表达式上使用功能索引(也称为MS SQL Server 中计算列上的索引)。仅仅有一个索引date_hour是不够的。

这个例子中,第二个表有一个计算列和一个索引(而第一个没有)。请注意相同的查询如何具有不同的执行计划,其中第一个实际对数据进行排序,而第二个只是快速浏览索引。

由于这是一个家庭作业,我会让您自己将其纳入您的示例中。

顺便说一句,如果您对索引和性能的主题感兴趣,我强烈推荐阅读:使用索引,卢克!

于 2012-05-29T19:20:37.697 回答
0

此查询将始终需要扫描。现在有 WHERE 子句,因此我们无法通过快速隔离较小的子集来加快查询速度。有一个 HAVING 子句,但它只能在聚合后应用。

但是有一个 GROUP BY 子句;可以通过添加适当的索引来加速 GROUP BY 子句的聚合。因为 GROUP BY 子句中的列也用于 SELECT 列表,所以我们可以实现只需要扫描该索引,而不是整个表。

GROUP BY 子句包含表达式month(date_hour)。这意味着我们可以忽略这个索引。仍然是乘客、航空公司、国籍、护照。在创建索引之前,您必须弄清楚正确的顺序。我的直觉是,您需要将最具选择性的列放在首位——也就是说,具有最多唯一值的列应该出现在具有较少唯一值的列之前。我猜乘客,航空公司,国籍,护照的顺序已经很不错了。那就是说我会通过改变列的顺序来做一些实验。

创建索引后,您将不必重写查询。但是,如果您的 RDBMS 的优化器是幼稚的(如 MySQL 的),您必须将 month(date_hour) 表达式作为 GROUP BY 子句的最后一个表达式。这不会以任何方式改变结果,尽管它可能会影响返回行的顺序。但是,这根本不重要(如果确实如此,您应该添加一个 ORDER BY 子句)

于 2012-05-29T19:20:19.223 回答
0

MasterTable 包含什么?似乎它会包含类似乘客的航段。如果是这样,很少有乘客在一个月内飞行超过 10 次。

您可以通过执行以下操作来提高性能:

(1) 在 MasterTable 中建立一个关于乘客的索引:

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  

这可能会加快查询速度。

但是,我会建议一些不同的东西。创建一个表格,按乘客(或类似级别)汇总信息以回答此类问题。当新数据添加到主表时,更新或插入行到该表中。

例如,您可能需要一个结构为 , , 的汇总表。晚上或每周运行一次此查询,它可能会回答很多问题。

于 2012-05-29T18:53:12.883 回答
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
于 2012-05-29T19:41:30.950 回答