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 || '%',但在这种情况下您不能使用额外的通配符。
我有一个字符集定义为 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 || '%',但在这种情况下您不能使用额外的通配符。