SQL的性能问题

SQL的性能问题,sql,oracle10g,Sql,Oracle10g,我有三个表地址、项目和项目位置 地址表: 项目位置表: 项目表: 我正在运行一个搜索条件:根据给定的地址查找a/b位置的项目。正如您所看到的,在项目的两列中有位置引用 要搜索的查询是: select Item.item_id, from Item, (select address_id, item_location_id from address, Item_location il where street_nm like '%zebra%' an

我有三个表地址、项目和项目位置

地址表:

项目位置表:

项目表:

我正在运行一个搜索条件:根据给定的地址查找a/b位置的项目。正如您所看到的,在项目的两列中有位置引用

要搜索的查询是:

select Item.item_id, 
from 
  Item, (select address_id, item_location_id 
         from address, Item_location il 
         where street_nm like '%zebra%' and street_nbr = 333 
           and il.address_id = address.address_id) addr
where 
    (addr.item_location_id = item.location_a or 
     addr.item_location_id = item.location_b)

这个查询运行非常慢,因为地址表上没有索引,我无法添加索引。还有什么我应该做的来提高速度的吗?现在,如果我使用地址表运行,返回结果大约需要20秒。

这是一个非常难看的查询。除了存在错误这一事实之外,您还忽略了许多最佳实践,尽管这可能不会显著提高性能,但编写易于阅读的查询将大大提高您将来维护查询的能力。第一件事:如果使用别名,那么应该一致地使用它们,包括为所有表添加别名和为所有列添加前缀。另外,你应该考虑一下间距。通过改变这两件事和其他一些问题,我们可以得到:

select  i.item_id
from    Item i,
    (select ad.address_id,
            il.item_location_id
     from address ad,
          Item_location il 
     where
           ad.street_nm like '%zebra%' and ad.street_nbr = 333 
           and il.address_id = ad.address_id) addr   
where
      addr.item_location_id = i.location_a 
      or addr.item_location_id = i.location_b
哇!这是这么多的可读性。现在,我可以清楚地看到,您使用的是不推荐使用的表联接版本,应该改为显式联接。另外,我可以清楚地看到,对于这个查询,您不需要子查询。删除子查询很可能会提高查询的性能—可能只是一点点,但我们喜欢所有的好处。让我们解决这些问题:

select  i.item_id
from    Item i
   join address ad 
       on (addr.item_location_id = il.location_a 
           or addr.item_location_id = il.location_b)
   join Item_location il 
       on il.address_id = ad.address_id
where
      ad.street_nm like '%zebra%' and ad.street_nbr = 333 
突然之间,情况看起来好多了。现在,我们可以在你的提问中深入探讨我认为最大的问题

on (addr.item_location_id = il.location_a 
or addr.item_location_id = il.location_b)
有趣的事实是,因为您在原始查询中没有选择任何内容或将其别名为location_a和location_b,所以它不会执行,您也会收到错误。我只是继续猜测,这会扼杀你的质疑。最初,我不能把这个大胖子或闲逛视为一种加入条件。我的建议是将其分为两个查询,并加入一个union all:

select  i.item_id
from    Item i
   join address ad 
       on addr.item_location_id = il.location_a 
   join Item_location il 
       on il.address_id = ad.address_id
where
      ad.street_nm like '%zebra%' and ad.street_nbr = 333

union all

select  i.item_id
from    Item i
   join address ad 
       on addr.item_location_id = il.location_b
   join Item_location il 
       on il.address_id = ad.address_id
where
      ad.street_nm like '%zebra%' and ad.street_nbr = 333

如果没有索引,我认为这个查询将是性能方面的最佳选择。即使它没有太快的速度,看看它有多漂亮!贵公司未来的开发人员将感谢您。

-20多年前,在ANSI-92 SQL标准中,旧样式的逗号分隔表样式已被正确的ANSI连接语法所取代,其使用也已过时discouraged@marc_s但是,我已经看到了一个争论,在堆栈中的某些地方同样存在溢出。对于较旧的连接方式与ANSI连接方式,性能没有多大关系。Ofcoz我将在同一页上进一步挖掘您的链接。每个表中分别有多少行?您希望返回多少行?考虑到这些数字,20秒似乎并不完全不合理。执行计划中可能存在瓶颈,但同样可能的是,这只是花在完全扫描和哈希连接上的时间——从技术上讲,根据列的数量及其类型,您的10M行表的大小可能约为100gb。您能用执行统计信息发布此查询的执行计划吗?示例:;向查询中添加“聚集\u计划\u统计信息”提示,并发布DBMS\u XPLAN.DISPLAY\u CUSROR输出。您的查询实际上看起来不太可读,更改或合并与更好的性能无关-您正在扫描同一个表两次。@当然,我认为连接条件中的或可能会有影响,但是你可能是对的,额外的扫描会导致更多的问题。如果我是OP,我可能会尝试一些方法,看看各种查询实际运行需要多长时间。请注意marc编辑前的查询。我想说,额外的间距绝对提高了可读性。@Behernow:这在很大程度上取决于引擎。在存在or联接的许多情况下,数据库将决定自己扫描表两次。
select  i.item_id
from    Item i
   join address ad 
       on (addr.item_location_id = il.location_a 
           or addr.item_location_id = il.location_b)
   join Item_location il 
       on il.address_id = ad.address_id
where
      ad.street_nm like '%zebra%' and ad.street_nbr = 333 
on (addr.item_location_id = il.location_a 
or addr.item_location_id = il.location_b)
select  i.item_id
from    Item i
   join address ad 
       on addr.item_location_id = il.location_a 
   join Item_location il 
       on il.address_id = ad.address_id
where
      ad.street_nm like '%zebra%' and ad.street_nbr = 333

union all

select  i.item_id
from    Item i
   join address ad 
       on addr.item_location_id = il.location_b
   join Item_location il 
       on il.address_id = ad.address_id
where
      ad.street_nm like '%zebra%' and ad.street_nbr = 333