我们有一个庞大的多表Sybase查询,我们称之为get_safari_exploration_data
查询,它可以获取与探险家相关的各种信息以及他们遇到的所有动物。
这个查询很慢,我被要求加快速度。跳出来的第一件事是,外部SELECT
子句中的嵌套FROM
语句似乎并不迫切。在嵌套的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
中的不必要字段?不幸的是,除非有无可辩驳的,事实证明将这个大型查询分解为较小的查询从长远来看是有益的,否则管理层根本不会批准将其重构为多个较小的查询,因为这将需要相当多的时间重构和测试。在此先感谢您的任何帮助/见解!
答案 0 :(得分:0)
我建议采用以下方法。
首先,使用带有on
子句的ANSI标准连接重写查询。这将使条件和过滤更容易理解。此外,这是“安全的” - 您应该得到与当前版本完全相同的结果。要小心,因为*=
是一个外连接,所以并非一切都是内连接。
我怀疑这一步将改善表现。
然后,检查每个引用表,并确保连接键上的索引在参考表中。如果缺少密钥,则将其添加进去。
然后,检查是否需要左外连接。桌子上有过滤器,左外连接。 。 。这些过滤器将外连接转换为内连接。可能不会影响性能,但你永远不会知道。
然后,考虑索引用于过滤的字段(在where
子句中)。
并且,学习如何使用解释功能。任何嵌套循环连接(没有索引)都可能成为性能问题的罪魁祸首。
至于嵌套选择,我认为Sybase足够聪明以“做正确的事”。即使它写出并重新读取结果集,与获得正确连接相比,这可能会对查询产生边际效应。
顺便说一下,如果这是你的真实数据结构,它听起来像一个非常有趣的领域。我通常不会在表格中看到名为allegator_id
的字段。
答案 1 :(得分:0)
在某些情况下,你会遇到这种情况,但是一个称职的策划者会崩溃它并在这里忽略它。
是的,特别是考虑到其中一些根本没有出现在最终的字段列表中。
就我所知,*=
和=*
只是左右连接的语法糖,但我说错了。如果没有,那么它们只是强制连接的方式发生,但它们可能是查询完全有效的必要条件。
是
首先,您需要进行一些不需要的计算,例如: convert (varchar(15), mp.rhino_id) as tms_id
。也许是一两个连接,但我承认没有看过查询的血腥细节。
接下来,您可能会遇到数据库设计本身的问题,例如:一个cow_id字段。 (说真的?:-))
最后,为了避免做大量的连接,偶尔会有一些关于进行多个查询而不是单个查询的事情。
例如,在博客中,抓住前10个帖子,然后使用单独的查询来获取其标签(其中id为(id1,id2等))通常是个好主意。在你的情况下,选择性部分似乎就在这里:
mp.exploring_strategy_id = 47
and mp.cow_id = ho.cow_id
and ho.cow_id IN (20, 30, 50)
因此,可以在一个查询中隔离该部分,然后使用生成的ID构建in ()
子句,并在一个或多个单独的查询中获取整容部分。
哦,正如Gordon指出的那样,检查你的索引。但是,请注意,如果不将查询拆分为更易于管理的部分,索引可能会很少使用。
答案 2 :(得分:0)
我会回答你的一些问题。
您认为嵌套SELECT中的字段(蔬菜,扫帚,吞噬)可能会导致性能问题。不必要。嵌套SELECT中的两个未使用的字段(vegetable,broomhilda)来自ts表,但正在使用的cat_metadata字段也来自ts表。因此,除非ts_ table上使用的索引覆盖了cat_metadata,否则不会对性能产生任何影响。因为,要提取cat_metadata字段,无论如何都需要获取表中的数据页。提取其他两个字段将占用很少的CPU,就是这样。所以不要担心。 '吞噬'字段也是一个常数。这也不会影响性能。
Dennis指出转换函数转换的使用(varchar(15),mp.rhino_id)。我不同意这会影响性能,因为它只会消耗CPU。
最后我会说,尝试使用set table count to 13,因为那里有13个表。 Sybase一次使用四个表进行优化。