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

firebird stored procedure not using index, but the same query does

我有一个字符集定义为 UTF8 的数据库。 table VSL_STATIC_DATA 带有一个名为 VESSEL_NAME 的 varchar(60) 字段,采用 UNICODE_CI_AI 排序规则,在该字段上具有升序索引。另一个名为 TABLE_PORTS 的 table,字段 PORT_ID 作为主键,它是 VSL_STATIC_DATA table ( PORT_OF_REG_ID)[=13 中的外键=]

当我 运行 以下查询时,它使用索引按名称搜索船只,然后使用索引 link 和注册端口:

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)

谁能指出我遗漏了什么? 仅供参考,这样做的目的是实现按名称增量搜索船只。

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

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

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

您需要一些方法来强制使用索引。

您可以尝试使用 开头:VSL_NAME 而不是 之类的:VSL_NAME || '%',但在这种情况下您不能使用额外的通配符。