【问题标题】:Is it possible to improve the performance of query with distinct and multiple joins?是否可以通过不同的连接和多个连接来提高查询的性能?
【发布时间】:2021-10-24 15:43:30
【问题描述】:

有如下查询:

SELECT DISTINCT ID, ACCOUNT,
   CASE
       WHEN p.GeneralLevel = '1' THEN '1'
       WHEN p.Level3 IS NULL THEN '2'
       WHEN p.Level4 IS NULL THEN '3'
       WHEN p.Level5 IS NULL THEN '4'
       WHEN p.Level6 IS NULL THEN '5'
       WHEN p.Level7 IS NULL THEN '6'
       WHEN p.Level8 IS NULL THEN '7'
       ELSE '8'
   END AS LEVEL,
   CASE
       WHEN c.codeValueDescription IS NULL THEN p.Level2
       ELSE c.codeValueDescription
   END AS L2_CODE,
   CASE
       WHEN d.codeValueDescription IS NULL THEN p.Level3
       ELSE d.codeValueDescription
   END AS L3_CODE,
   CASE
       WHEN j.codeValueDescription IS NULL THEN p.Level4
       ELSE j.codeValueDescription
   END AS L4_CODE,
   CASE
       WHEN f.codeValueDescription IS NULL THEN p.Level5
       ELSE f.codeValueDescription
   END AS L5_CODE,
   CASE
       WHEN g.codeValueDescription IS NULL THEN p.Level6
       ELSE g.codeValueDescription
   END AS L6_CODE,
   CASE
       WHEN h.codeValueDescription IS NULL THEN p.Level7
       ELSE h.codeValueDescription
   END AS L7_CODE,
   p.Level8
   FROM generic p
   LEFT JOIN
     (SELECT codeValue, codeValueDescription
      FROM codes
      WHERE code = '2') c ON p.Level2 = c.codeValue
   LEFT JOIN
     (SELECT codeValue, codeValueDescription
      FROM codes
      WHERE code = '3') d ON p.Level3 = d.codeValue
   LEFT JOIN
     (SELECT codeValue, codeValueDescription
      FROM codes
      WHERE code = '4') j ON p.Level4 = j.codeValue
   LEFT JOIN
     (SELECT codeValue, codeValueDescription
      FROM codes
      WHERE code = '5') f ON p.Level5 = f.codeValue
   LEFT JOIN
     (SELECT codeValue, codeValueDescription
      FROM codes
      WHERE code = '3') g ON p.Level6 = g.codeValue //yes, code is 3 again
   LEFT JOIN
     (SELECT codeValue, codeValueDescription
      FROM codes
      WHERE code = '3') h ON p.Level7 = h.codeValue //and yes, again code 3 here

“通用”表的某些列(排除日期和其他对我们不重要的列):

ID INTEGER NOT NULL,
ACCOUNT VARCHAR(50) NOT NULL,
GeneralLevel1 VARCHAR(50),
Level2 VARCHAR(50),
Level3 VARCHAR(50),
Level4 VARCHAR(50),
Level5 VARCHAR(50),
Level6 VARCHAR(50),
Level7 VARCHAR(50),
Level8 VARCHAR(50)

简单数据:

ID,ACCOUNT_ID,LEVEL_1,LEVEL_2,...LEVEL_8
id1,ACCOUNT_ID1,GENERAL,null,...null
id1,ACCOUNT_ID2,GENERAL,A,...null
id1,ACCOUNT_ID2,GENERAL,B,...null
id2,ACCOUNT_ID1,GENERAL,null,...null
id2,ACCOUNT_ID2,GENERAL,A,...null
id2,ACCOUNT_ID3,GENERAL,B,...H

当前查询运行超过 1s,通常返回 100 到 1000 条记录,我想提高这个查询的性能。我们的想法是摆脱这些 LEFT JOINS 并以某种方式重写此查询以提高性能。

也许有办法改进这个查询以更快地获取数据?我希望我在这里提供了足够的信息。数据库是自定义的,引擎盖下的 NO_SQL 巨人,但我们的数据库桥的语法与 MySQL 非常相似。不幸的是,我无法提供此查询的执行计划,因为它正在服务器端进行处理,然后生成一些我无法访问的 SQL。

【问题讨论】:

  • 提示:coalesce(c.codeValueDescription, p.Level2).
  • 您使用的是哪个 dbms?
  • @jarlh:让我们认为语法与 MySQL 中的几乎相同,我们使用自定义 db..
  • 我们如何知道您的自定义数据库的优化和性能技巧?
  • 尝试将左连接重构为 LEFT JOIN codes c ON c.code= '2' and p.Level2 = c.codeValue 。当p.LevelXnull 时,它可能会消除(如果查询优化器不够聪明,无法自行完成)搜索codes

标签: sql join left-join query-optimization key-value


【解决方案1】:

您正在从codes 表中进行键/值查找。您的查询包含其中几个 LEFT JOIN 模式。

   FROM generic p
   LEFT JOIN
     (SELECT codeValue, codeValueDescription
      FROM codes
      WHERE code = '2') c ON p.Level2 = c.codeValue
   LEFT JOIN
     (SELECT codeValue, codeValueDescription
      FROM codes
      WHERE code = '3') d ON p.Level3 = d.codeValue

这些 LEFT JOIN 可以重构以消除子查询。这种重构可能会更清楚地向 SQL 系统表明您的意图。结果如下所示。

   FROM generic p
   LEFT JOIN codes c ON  p.Level2 = c.codeValue AND c.code = '2'
   LEFT JOIN codes d ON  p.Level3 = d.codeValue AND d.code = '3'

如果您的 SQL 系统允许索引,那么在您的 codes 表上使用这样的覆盖索引将有助于加快您的键/值查找。

ALTER TABLE codes ADD INDEX (codeValue, code, codeValueDescription)

您的 SELECT 子句包含很多此类内容:

   CASE
       WHEN c.codeValueDescription IS NULL THEN p.Level2
       ELSE c.codeValueDescription
   END AS L2_CODE,
   CASE
       WHEN d.codeValueDescription IS NULL THEN p.Level3
       ELSE d.codeValueDescription
   END AS L3_CODE

它可能没有多大帮助,但这可以通过将其重写为来简化

   COALESCE(c.codeValueDescription, p.Level2) AS L2_CODE,
   COALESCE(d.codeValueDescription, p.Level3) AS L3_CODE

如果消除 DISTINCT 限定符会发生什么?这可能需要一些处理时间。如果您的 generic.ID 列是主键,那么 DISTINCT 对您没有好处:这些列值不会重复。 (大多数现代 SQL 查询规划器会检测到这种情况并跳过重复数据删除步骤,但我们不知道您的查询规划器有多现代。)

您的查询不包含整体WHERE 子句,因此它必须处理generic 表中的每一行。而且,如果该表很大,您的结果集也会很大。我相信您知道,扫描整个大表需要时间和资源。

话虽如此,通过 SQL 桥接这样的查询每行一毫秒并不是吸烟枪般可怕的性能。你可能不得不忍受它。另一种方法可能是将代码应用于应用程序中的数据:slurp 整个codes 表,然后编写一些应用程序逻辑来执行 CASE / WHEN / THEN 或 COALESCE 工作。换句话说,将 LEFT JOIN 操作移至您的应用程序。如果您的 SQL 桥能够快速处理简单的 SELECT * FROM generic 单表查询,这将有很大帮助。

【讨论】:

  • 非常有帮助,很长,非常感谢,在获取数据后将尝试在 lambda 中实现 case/when/then。你认为如果移动到应用程序级别,它是否有助于查询中的左连接/应用程序中的左连接?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-05
相关资源
最近更新 更多