【问题标题】:How would you optimize this query您将如何优化此查询
【发布时间】:2020-08-21 12:33:45
【问题描述】:

我在 VFP9 中(是的,我知道)下一个查询运行良好,但是使用大小为 20mb(或 9k 行)的 DBF(表)在游标上创建一个大于 2gb 的临时文件(并且这会使 VFP9 因 32 位而崩溃)

            SELECT DISTINCT t1.*;
            FROM t1,t2;
            WHERE ALLTRIM(t1.name) = ALLTRIM(t2.name);
            AND ALLTRIM(t1.name2) = ALLTRIM(t2.name2);
            AND t1.tyc = t2.tyc;
            AND t1.nc = t2.nc;
            AND t1.forced = 0;
            AND t1.secuence NOT in (Select secuence FROM t2);   
            Into Cursor cursordel

我只放这段代码是因为它有效,除非我有超过 2k 的行 我认为用 join 替换“not in”可以解决问题,但没有奏效,或者至少没有我尝试过的方式......

【问题讨论】:

  • 附带说明:您可以通过使用ALLTRIM 更新表中的所有行一次并安装对任何插入或更新的行执行相同操作的触发器来避免查询中的ALLTRIM
  • 查询正在查找所有 t1,其中 t2 中的 tyc、nc 和名称匹配,但 t2 中没有匹配序列。 也许它的真正目的是检查 t2 中是否存在与 tyc、nc 和名称的匹配,但与另一个序列。好吧,也许也许不是。我当然不能知道。如果是这种情况,您只需要一次查找而不是两次。除此之外,请按照 Gordon 的建议使用 EXISTS 进行查找并提供他提到的索引。
  • @ThorstenKettner,用 alltrim() 更新所有行将是一个没有意义的操作,除非它是 LTRIM() - 这不太可能。
  • @Cetin Basoz:我不明白为什么这毫无意义。 ALLTRIM 删除 FoxPro 中的前导和尾随空格。你为什么要那些名字呢?如果它们总是被触发器立即删除(加上对现有数据的每次更新一次),查询中将不再需要ALLTRIM,甚至可以在这些列上提供有用的索引以便更快地查找。
  • @ThorstenKettner,这毫无意义,因为 OP 在他的问题中说 VFP 和 DBF。虽然,VFP 支持 Varchar(不是真的),但 99.999% 的 DBF 将字符字段作为 Char 字段,而不是 Varchar 字段。这意味着 ALLTRIM() 只是意味着 LTRIM() 并且结果文本仍然与尾随空格相同。 IOW,它不能帮助您删除存储数据中的尾随空格。我相信,OP 对 ALLTRIM() 的使用实际上没有任何目的(可能他想确保有一个完全匹配,他可以简单地使用 == 或设置 ANSI ON)。我不想要名称中的某些内容,我更喜欢使用索引。

标签: sql optimization visual-foxpro


【解决方案1】:

假设第一个表没有重复,我将其表述为not exists

SELECT t1.*
FROM t1
WHERE NOT EXISTS (SELECT 1
                  FROM t2
                  WHERE ALLTRIM(t1.name) = ALLTRIM(t2.name) AND
                        ALLTRIM(t1.name2) = ALLTRIM(t2.name2) AND
                        t1.tyc = t2.tyc AND
                        t1.nc = t2.nc
                ) AND
      t1.forced = 0 AND
      NOT EXISTS (SELECT 1
                  FROM t2
                  WHERE t2.secuence = t1.secuence
                 );  

那么对于这个查询,您需要t2(tyc, nc, name, name2)t2(secuence) 上的索引。我怀疑t1(forced) 上的索引会有所帮助,除非该列很少是0

即使没有索引,这也消除了外部SELECT DISTINCT

请注意,t2 上的 NOT IN 条件看起来很可疑。为什么它也不需要匹配条件?

【讨论】:

  • 您好,感谢您的回答。是的,第一个表没有重复项,第二个表也没有,我注意到这是一个非常奇怪的查询,但它是一个大代码和有效方法中的查询,我不写这个,不是我的代码,但我正在工作在上面。这似乎工作得很好,我必须做一些其他的测试,但似乎进展顺利,谢谢!当我确定时,我会标记为答案。
  • 我有一个问题,虽然这是一个小问题,但我无法解决它,当我使用这个解决方案时,说“错误关联字段”,但如果我删除 where 子句中的两个字符串 ( name 和 name2) 它可以工作,但是 IDK 如果改变全局过程的结果,你知道什么会导致这个错误吗?
  • @Synystter 。 . .你可能需要用LEFT JOIN 做什么组件,唉。
  • 我认为原始查询正在寻找所有 t1,其中 t2 在 tyc、nc 和名称上有匹配,但在 t2 中没有匹配序列。因此,您的第一个 NOT EXISTS 应该是 EXISTS
  • @GordonLinoff,如果您使用 ALLTRIM(),那么您不需要这些字段的索引,因为它们无论如何都不会被使用,不是吗?他实际上并没有给出优化所需的所有细节(即表结构和索引)。猜测一下,ALLTRIM() 应该是 RTRIM(),它是无用的并且会阻止索引的使用(带有 ALLTRIM() 的索引是没有意义的)。
【解决方案2】:

这看起来你可以做一个内部连接,我不知道 fox pro 如何处理光标中的交叉连接听起来交叉连接在这里造成了破坏:在未修剪的交叉连接中,9,000 行,20mb 是一个超过 2 GB,但听起来这可能会有所帮助:

SELECT;
        DISTINCT t1.*;
        FROM t1; 
        inner join t2 on
        ALLTRIM(t1.name) = ALLTRIM(t2.name)
        AND ALLTRIM(t1.name2) = ALLTRIM(t2.name2)
        AND t1.tyc = t2.tyc
        AND t1.nc = t2.nc
        AND t1.forced = 0
        AND t1.secuence NOT in (Select secuence FROM t2)
        Into Cursor cursordel

【讨论】:

  • 你好,谢谢你的回答,我明白你的逻辑了,但是很遗憾,VFP 似乎不支持这个
【解决方案3】:

为什么首先需要区分?当您只想进行 EXISTS 检查时,为什么要创建隐式交叉联接然后进行过滤?而且,这些 alltrim() 的目的是什么?你的领域有领先的空间吗?还是您的意思是修剪尾随空格?如果是后者,则完全没有必要,而且还会阻止使用可能存在的索引。

SELECT * ;
            FROM t1 ;
            WHERE t1.forced = 0 ; 
            and EXISTS (select * from t2 ;
              where t1.name == t2.name ;
                AND t1.name2  == t2.name2 ;
                AND t1.tyc == t2.tyc ;
                AND t1.nc == t2.nc ) ;
            and not EXISTS (select * from t2 where t1.secuence = t2.secuence) ;
            Into Cursor cursordel ;
            NOFILTER

【讨论】:

    猜你喜欢
    • 2017-03-01
    • 2023-04-02
    • 1970-01-01
    • 2017-02-07
    • 2021-09-09
    相关资源
    最近更新 更多