2

我试图理解为什么第一个查询会比第二个查询快:

SELECT * FROM DBADMIN.CR_TICKET WHERE QUEUE_ID=005555 AND STATUS=4

SELECT TICKET_ID FROM DBADMIN.CR_TICKET WHERE QUEUE_ID=005555 AND STATUS=4

第一个运行大约需要一分钟并返回所有字段。第二个我只是在几分钟后停下来,因为它花了太长时间。TICKET_ID 是有效的列名。我是数据库和 sql 的新手,并且使用 vb.net 并参考了 oracle 即时客户端 11。

Using connection As New OracleConnection()
        Dim command As OracleCommand = connection.CreateCommand()
        Dim reader As OracleDataReader = command.ExecuteReader()
        Dim str As String
        Dim strFieldName As String
        Dim strFieldType As String
        Dim sql As String = "SELECT * FROM DBADMIN.CR_TICKET WHERE QUEUE_ID=005555 AND STATUS=4"

        connection.ConnectionString = connectionString
        connection.Open()

        command.CommandText = sql

        While reader.Read()
            str = ""
            strFieldName = ""
            strFieldType = ""

            For e = 0 To reader.FieldCount - 1
                strFieldName = reader.GetName(e)
                strFieldType = reader.GetDataTypeName(e)
                str = str & strFieldName & " " & strFieldType & ": " & reader(e).ToString & vbCrLf

            Next

            Console.Write(str & vbCrLf & vbCrLf)
        End while

2013 年 3 月 4 日更新:

首先感谢您的出色建议,我最终能够让 sql plus 运行并返回以下执行计划。我昨天做了很多阅读,发现我的查询速度很慢的原因之一是我正在搜索的列没有被索引。我发现主键列(存在于每个表中)默认情况下是索引的。我将我的 sql 字符串更改为:

SQL> SELECT * FROM DBADMIN.CR_TICKET WHERE TICKET_ID > 'CR00000000' AND STATUS=4 AND (QUEUE_ID=005555 OR QUEUE_ID=005556) ORDER BY PRIORITY, TROUBLE_START;


| Id  | Operation                    | Name        | Rows  | Bytes | Cost (%CPU)

| Time     |

--------------------------------------------------------------------------------

------------

|   0 | SELECT STATEMENT             |             |     1 |   401 |     6  (17)

| 00:00:01 |

|   1 |  SORT ORDER BY               |             |     1 |   401 |     6  (17)

| 00:00:01 |

|*  2 |   TABLE ACCESS BY INDEX ROWID| CR_TICKET   |     1 |   401 |     5   (0)

| 00:00:01 |

|*  3 |    INDEX RANGE SCAN          | CRT_TID_IDX |     1 |       |     4   (0)

 | 00:00:01 |

--------------------------------------------------------------------------------

这运行得相当快。我了解到我的原始查询正在读取数据库中的每条记录以匹配我的陈述。通过稍微不同地构造查询以包含索引列,它基本上只搜索主数据库的一部分。

SQL> SELECT * FROM DBADMIN.CR_TICKET WHERE QUEUE_ID=005555 AND STATUS=4 AND PRIORITY=1;

| Id  | Operation                   | Name         | Rows  | Bytes | Cost (%CPU)

| Time     |

--------------------------------------------------------------------------------

------------

|   0 | SELECT STATEMENT            |              |     1 |   401 | 14864   (1)

| 00:02:59 |

|*  1 |  TABLE ACCESS BY INDEX ROWID| CR_TICKET    |     1 |   401 | 14864   (1)

| 00:02:59 |

|*  2 |   INDEX RANGE SCAN          | CRT_STAT_IDX |   230K|       |   408   (2)

| 00:00:05 |



SQL> SELECT DBADMIN.CR_TICKET.TICKET_ID FROM DBADMIN.CR_TICKET WHERE    QUEUE_ID=005555     AND STATUS=4 AND PRIORITY=1;


| Id  | Operation                   | Name         | Rows  | Bytes | Cost (%CPU)

| Time     |

--------------------------------------------------------------------------------

------------

|   0 | SELECT STATEMENT            |              |     1 |    24 | 14845   (1)

| 00:02:59 |

|*  1 |  TABLE ACCESS BY INDEX ROWID| CR_TICKET    |     1 |    24 | 14845   (1)

| 00:02:59 |

|*  2 |   INDEX RANGE SCAN          | CRT_STAT_IDX |   230K|       |   408   (2)

| 00:00:05 |

--------------------------------------------------------------------------------

2013 年 5 月 25 日更新

感谢您提供帮助,我很感激。我终于有机会重新审视这个项目并尝试了您建议的查询。第一个运行良好,第二个没有返回任何结果。您提到了索引功能。这会在数据库上创建一个永久索引吗?我不想那样做。

select status, priority, count(*)
from dbadmin.cr_ticket
group by status, priority;

数据库查询1

4

1 回答 1

1

我们需要对这两个查询制定解释计划,以便为您提供真正的答案。

要获得解释计划,您可以通过 SQL*Plus 连接到数据库并键入以下内容:

set lines 155
set page 999
explain plan for
SELECT * 
  FROM DBADMIN.CR_TICKET 
 WHERE QUEUE_ID=005555 
   AND STATUS=4;

@?/rdbms/admin/utlxpls

执行上述操作并不危险,您没有修改任何内容。你甚至没有运行实际的查询。如果您有 SQL Developer 或 Toad 之类的图形工具,您只需选择代码,您应该能够在菜单中找到“显示解释计划”。在 Toad 中,您可以按 ctrl+e。

现在我怀疑表或索引上的统计信息已经过时了。您可能有一个包含“TICKED_ID”的索引,在 Oracle 看来它看起来“不错”,但实际上并非如此。更改为“SELECT *”很可能意味着没有“覆盖”索引可供使用,Oracle 可能会选择另一个更合适的索引。

同样,这只是猜测工作。给我们两个查询的计划,我们会帮助你:)

2013-03-05 编辑

您可能不应该这样做WHERE TICKET_ID > 'CR00000000',因为它采用某种格式。例如,如果您插入 TICKET_ID='A1' 的记录,它将不起作用。

在不了解更多信息的情况下,我会说 {queue_id, priority} 上的索引可能是一个不错的候选者。但是,如果您的数据看起来像我认为的那样,那么只有一小部分的状态 = 4,然后您应该受益于使用基于函数的索引

它看起来像这样:

create index dbadmin.cr_ticket_fbx_stat_4
    on dbadmin.cr_ticket(case when status = 4 then 4 end);

此索引与状态列上的普通索引之间的区别在于,这里只有 status = 4 的行实际上会被索引。因此,如果您的表有 1,000,000 行,并且只有 1,000 行的状态 = 4,则索引中将仅存在 1,000 个条目。它真的很小。要使用索引,您需要将查询编写为:

select *
  from dbadmin.cr_ticket
 where (case when status = 4 then 4 end) = 4;

如果您可以提供以下查询的结果,我可以给您更多建议:

select status, priority, count(*)
  from dbadmin.cr_ticket
group by status, priority;

select avg(count(*)), median(count(*)), min(count(*)), max(count(*))
  from dbadmin.cr_ticket
 group by queue_id;

select count(*), count(distinct queue_id)
  from dbadmin.cr_ticket; 
于 2013-03-03T22:38:10.093 回答