【发布时间】:2013-04-19 17:32:02
【问题描述】:
我们有一个庞大的多表 Sybase 查询,我们称之为 get_safari_exploration_data 查询,它获取与探险者进行 safari 以及他们遇到的所有动物相关的各种信息。
这个查询很慢,我被要求加快速度。我首先想到的是,在外部 FROM 子句中似乎并不迫切需要嵌套的 SELECT 语句。在嵌套的SELECT 中,似乎还有几个不需要的字段(vegetable、broomhilda、devoured 等)。我也对连接的使用持怀疑态度(“*=”而不是“INNER JOIN...ON”)。
SELECT
dog_id,
cat_metadata,
rhino_id,
buffalo_id,
animal_metadata,
has_4_Legs,
is_mammal,
is_carnivore,
num_teeth,
does_hibernate,
last_spotted_by,
last_spotted_date,
purchased_by,
purchased_date,
allegator_id,
cow_id,
cow_name,
cow_alias,
can_be_ridden
FROM
(
SELECT
mp.dog_id as dog_id,
ts.cat_metadata + '-yoyo' as cat_metadata,
mp.rhino_id as rhino_id,
mp.buffalo_id as buffalo_id,
mp.animal_metadata as animal_metadata,
isnull(mp.has_4_Legs, 0) as has_4_Legs,
isnull(mp.is_mammal, 0) as is_mammal,
isnull(mp.is_carnivore, 0) as is_carnivore,
isnull(mp.num_teeth, 0) as num_teeth,
isnull(mp.does_hibernate, 0) as does_hibernate,
jungle_info.explorer as last_spotted_by,
exploring_journal.spotted_datetime as last_spotted_date,
jungle_info.explorer as purchased_by,
early_exploreration_journal.spotted_datetime as purchased_date,
alleg_id as allegator_id,
ho.cow_id,
ho.cow_name,
ho.cow_alias,
isnull(mp.is_ridable,0) as can_be_ridden,
ts.cat_metadata as broomhilda,
ts.squirrel as vegetable,
convert (varchar(15), mp.rhino_id) as tms_id,
0 as devoured
FROM
mammal_pickles mp,
very_tricky_animals vt,
possibly_venomous pv,
possibly_carniv_and_tall pct,
tall_and_skinny ts,
tall_and_skinny_type ptt,
exploration_history last_exploration_history,
master_exploration_journal exploring_journal,
adventurer jungle_info,
exploration_history first_exploration_history,
master_exploration_journal early_exploreration_journal,
adventurer jungle_info,
hunting_orders ho
WHERE
mp.exploring_strategy_id = 47
and mp.cow_id = ho.cow_id
and ho.cow_id IN (20, 30, 50)
and mp.rhino_id = vt.rhino_id
and vt.version_id = pv.version_id
and pv.possibly_carniv_and_tall_id = pct.possibly_carniv_and_tall_id
and vt.tall_and_skinny_id = ts.tall_and_skinny_id
and ts.tall_and_skinny_type_id = ptt.tall_and_skinny_type_id
and mp.alleg_id *= last_exploration_history.exploration_history_id
and last_exploration_history.master_exploration_journal_id *= exploring_journal.master_exploration_journal_id
and exploring_journal.person_id *= jungle_info.person_id
and mp.first_exploration_history_id *= first_exploration_history.exploration_history_id
and first_exploration_history.master_exploration_journal_id *= early_exploreration_journal.master_exploration_journal_id
and early_exploreration_journal.person_id *= jungle_info.person_id
) TEMP_TBL
所以我问:
- 我对嵌套的
SELECT是否正确? - 我是否纠正了嵌套
SELECT中不必要的字段? - 我对连接的结构/语法/用法是否正确?
- 关于这个查询的结构/性质,还有什么其他让您觉得效率低下/速度慢的地方吗?
不幸的是,除非有无可辩驳的事实证明,从长远来看,将这个大型查询分解为更小的查询是有益的,否则管理层根本不会批准将其重构为多个更小的查询,因为这将花费大量时间是时候重构和测试了。在此先感谢您提供的任何帮助/见解!
【问题讨论】:
-
嵌套的 SELECT 可能会也可能不会提供性能影响。这取决于执行计划(我不能告诉你,因为要建模的表很多)。如果它使用的是临时表,那么一定要删除嵌套的 SELECT(您可以使用 EXPLAIN 计划找到)。否则,额外的字段不会伤害任何东西,除非它们需要不必要的连接。同样,这取决于执行计划是否使用临时表(如果子查询没有首先复制到临时表,优化器将从查询中删除不必要的表)。
-
感谢 @jtv4k (+1) - 澄清一下,您是说 if 执行计划(我可以通过
EXPLAIN看到)显示 Sybase 使用TEMP_TBL,那我肯定要去掉嵌套的SELECT?如果这就是你的意思,你能解释为什么嵌套的SELECT和关联的TEMP_TBL对执行计划来说是“坏”(慢)吗? -
啊,我开始“明白”了。如果我理解正确:如果子查询被复制到临时表,那么优化器将不会删除不必要的连接;否则不必要的连接将作为执行计划的一部分保留,它们会对性能产生不利影响? 这是一个公平的评估吗?再次感谢!
-
这是个玩笑吗?如果是的话,那就太搞笑了!
-
这有“管理”?!?
标签: sql performance optimization sybase