firebird存储过程不使用索引,但查询相同

时间:2015-03-02 10:39:10

标签: sql firebird firebird2.5

我有一个数据库,其中字符集定义为UTF8。一个带有varchar(60)字段的表VSL_STATIC_DATA,该字段名为VESSEL_NAME,具有UNICODE_CI_AI排序规则,该字段上有一个升序索引。另一个名为TABLE_PORTS的表,其字段PORT_ID为主键,即VSL_STATIC_DATA表中的FK(PORT_OF_REG_ID)

当我运行以下查询时,它使用索引按名称搜索容器,然后使用索引链接到注册表端口:

SELECT FIRST (5) SKIP (0)
  VSL.VESSEL_ID,
  VSL.UPDATE_TIME,
  VSL.VESSEL_NAME,
  VSL.CALL_SIGN,
  VSL.MMSI,
  VSL.IMO_NUM,
  VSL.LOA,
  VSL.WIDTH,
  VSL.NRT,
  VSL.GRT,
  VSL.DWT,
  PORT.PORT_ID,
  PORT.PORT_NAME
FROM
  VSL_STATIC_DATA VSL     
LEFT JOIN
  TABLE_PORTS PORT
    ON VSL.PORT_OF_REG_ID = PORT.PORT_ID
WHERE VSL.VESSEL_NAME LIKE 'TE%'

但是,如果现在我将完全相同的查询放在存储过程中:

CREATE PROCEDURE FIND_VESSEL_BY_NAME(
  VSL_NAME VARCHAR(60),
  FIRST_N INTEGER,
  SKIP_N INTEGER)
RETURNS(
  VESSEL_ID BIGINT,
  UPDATE_TIME BIGINT,
  VESSEL_NAME VARCHAR(60),
  CALL_SIGN VARCHAR(10),
  MMSI BIGINT,
  IMO INTEGER,
  LOA SMALLINT,
  WIDTH SMALLINT,
  NRT INTEGER,
  GRT INTEGER,
  DWT INTEGER,
  PORT_OF_REG_ID BIGINT,
  PORT_OF_REG VARCHAR(75))
AS
BEGIN
  /* Procedure body */
  FOR
    SELECT FIRST (:FIRST_N) SKIP (:SKIP_N)
      VSL.VESSEL_ID,
      VSL.UPDATE_TIME,
      VSL.VESSEL_NAME,
      VSL.CALL_SIGN,
      VSL.MMSI,
      VSL.IMO_NUM,
      VSL.LOA,
      VSL.WIDTH,
      VSL.NRT,
      VSL.GRT,
      VSL.DWT,
      PORT.PORT_ID,
      PORT.PORT_NAME
    FROM
      VSL_STATIC_DATA VSL     
    LEFT JOIN
      TABLE_PORTS PORT
        ON VSL.PORT_OF_REG_ID = PORT.PORT_ID
    WHERE VSL.VESSEL_NAME LIKE :VSL_NAME || '%'
    INTO
      :VESSEL_ID,
      :UPDATE_TIME,
      :VESSEL_NAME,
      :CALL_SIGN,
      :MMSI,
      :IMO,
      :LOA,
      :WIDTH,
      :NRT,
      :GRT,
      :DWT,
      :PORT_OF_REG_ID,
      :PORT_OF_REG
  DO
  SUSPEND;
END;

这不使用索引。我用这个sql调用它:

select * from find_vessel_by_name( 'te', 10, 0)

任何人都可以指出我缺少的东西吗? 仅供参考,其目的是按名称实施船舶增量搜索。

2 个答案:

答案 0 :(得分:2)

您可以尝试使用以:VSL_NAME 开头,而不是,例如:VSL_NAME || '%',但在这种情况下,您无法使用其他野人。

答案 1 :(得分:1)

VESSEL_NAME上的索引不能在存储过程中使用,因为绑定变量(可能还有||操作 - 优化器有时并不完美。)

回想一下,计划计算一次,但对任何输入执行。

考虑例如find_vessel_by_name('%te',...) - 这里索引没用。 find_vessel_by_name(NULL,...) - 应该做什么?

您需要某种方法来强制使用索引。