gpt4 book ai didi

sql - 为什么索引不与子查询一起使用

转载 作者:行者123 更新时间:2023-12-04 19:08:51 25 4
gpt4 key购买 nike

这需要 0.001 秒来执行,它使用索引查找

SELECT * FROM CUSTOMER WHERE ID IN (1008,1122)

现在我有一个存储过程 U_VIP,它返回与示例一相同的 ID (1008,1122),执行只需 0.001 秒
SELECT ID FROM U_VIP    //returns (1008,1122)

现在当我组合它们时,执行大约需要半秒并且不使用索引
SELECT * FROM CUSTOMER WHERE ID IN (SELECT ID FROM U_VIP)

我已经简化了上面的例子,在实际应用中,性能受到更高幅度的影响。在这种情况下如何强制 Firebird 使用索引?

**使用火鸟 2.1

** 编辑 **

根据 Mark 的回答,使用 JOIN 确实可以提高执行时间,因为它现在正在进行索引查找。
SELECT CUSTOMER.* 
FROM CUSTOMER
INNER JOIN U_VIP ON U_VIP.ID = CUSTOMER.ID

这很好,但是,它给我带来了另一个问题,我将在下面的示例中尝试解释。
SELECT CUSTOMER.* 
FROM CUSTOMER
WHERE (:AREAID = 0 OR ID IN (SELECT ID FROM U_VIP(:AREAID)))

使用 where 子句,我可以根据用户是否提供 :AREAID 有条件地应用过滤器。当我用连接替换 where 子句时,如何实现相同的效果?

就像是:
SELECT CUSTOMER.* 
FROM CUSTOMER
{IF :AREAID > 0 THEN}
INNER JOIN (SELECT ID FROM U_VIP(:AREAID)) VIP ON VIP.ID = CUSTOMER.ID
{END IF}

当然,Firebird 不喜欢带大括号的部分 =/

最佳答案

而不是 IN , 你需要使用 EXISTSINNER JOIN .我不完全确定细节,但我相信您的查询 CUSTOMER表被完全读取,评估每一行的子查询结果(甚至可能为每一行执行子查询)。由于优化器事先不知道子查询的结果数量,因此如果您像在第一个查询中那样使用固定数量的文字值,它就无法像它那样创建优化。
尝试将您的查询更改为:

SELECT * 
FROM CUSTOMER
WHERE EXISTS (SELECT 1 FROM U_VIP WHERE U_VIP.ID = CUSTOMER.ID)
或者:
SELECT CUSTOMER.* 
FROM CUSTOMER
INNER JOIN U_VIP ON U_VIP.ID = CUSTOMER.ID
或者(有时更改顺序可以带来更好的性能):
SELECT CUSTOMER.* 
FROM U_VIP
INNER JOIN CUSTOMER ON CUSTOMER.ID = U_VIP.ID
一般来说,我希望这些查询比使用 IN 的查询执行得更好。 .
编辑以响应更新
根据您更新的问题,我可以想到多种解决方案,但我并不完全确定它们的性能。
  • :AREAID 使用单独的查询为 0 和 :AREAID不是 0
  • 使用存储过程或 EXECUTE BLOCK EXECUTE STATEMENT使用动态构建的语句(前一个的变体)
  • 如果 :AREAID 则使存储过程 U_VIP 返回所有客户是 0
  • 使用额外的 JOIN条件 OR :AREAID = 0 ;如果 U_VIP 不为 0 返回任何结果,这可能不会产生结果(并且可能不会执行 *)
  • 使用 LEFT JOIN并添加 WHERE U_VIP.ID IS NOT NULL OR :AREAID = 0 (可能不执行*)
  • 使用 UNION '普通'查询和第二个查询 CUSTOMERWHERE :AREAID = 0 (可能不执行*)

  • 对于 (*) 'Smart logic'反模式
    对于动态构建的查询,您可以考虑以下内容:
    EXECUTE BLOCK (INPUTCONDITION INTEGER = ?)
    RETURNS (ID INTEGER)
    AS
    DECLARE VARIABLE QUERY VARCHAR(6400);
    BEGIN
    QUERY = 'SELECT a.ID FROM SORT_TEST a';
    IF (INPUTCONDITION <> 0) then
    QUERY = QUERY || ' WHERE a.ID = ' || INPUTCONDITION;
    FOR EXECUTE STATEMENT QUERY INTO :ID
    DO
    SUSPEND;
    END
    在本例中, INPUTCONDITION 的值为 0将生成不带 WHERE 的查询- 子句,对于其他输入,使用 WHERE 进行查询-条款。如果参数是 (VAR)CHAR,那么这样做很容易导致 SQL 注入(inject)。或 BLOB ,所以要小心。您还可以考虑两个分支,其中一个使用 EXECUTE STATEMENT 带参数,其他不带。
    而不是 EXECUTE BLOCK ,您也可以使用您已经使用的可选程序 U_VIP ; EXECUTE BLOCK本质上是一个不存储在数据库中的存储过程。
    另见 'Myth: dynamic SQL is slow'

    关于sql - 为什么索引不与子查询一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17715521/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com