【问题标题】:Can I improve performance of a query if I use several subqueries and use their results as condition for the main query?如果我使用多个子查询并将它们的结果用作主查询的条件,是否可以提高查询的性能?
【发布时间】:2018-12-14 15:40:16
【问题描述】:

(首先解释了很多,实际问题在帖子末尾相当短)

这是初始情况: 我们正在开发一个软件,它从 sqlite 数据库中查询数据并将它们绘制在不同的图表中(LineChart,BarChart,...) 这个想法是用户可以选择 X 轴和 Y 轴的列以及过滤器的任何组合,软件将创建一个查询,获取数据并绘制它。 现在我们想稍微提高一下查询的性能。为此,我使用软件从随机图中计算的查询并在DB Browser 中对其进行测试,看看需要多长时间。然后我尝试手动更改查询,看看是否可以改进时间。

对于这个测试,我们使用一个带有多个过滤器的大型(用于 sqlite)数据库(1.4Gb 数据库大小,大约 35Mio 行/6 列我们想要从中获取结果的表。

我们有 3 个链接表 EmdTableShmooTableResultTable。 该软件给了我以下查询(从调试复制并删除了字符串转义字符):

SELECT (R0), AVG(R1) FROM 
(SELECT (EmdTable."Time [ns]") AS R0, (EmdTable."Upper Sideband [mV]" ) AS R1 FROM EmdTable, ResultTable, ShmooTable 
WHERE EmdTable."ResultID"=ResultTable."ID" 
AND ResultTable."ShmooID"=ShmooTable."ID" 
AND ResultTable."CommandName"="APDU: Get PO" 
AND ResultTable."Repetition"="1" 
AND ResultTable."StepName"="Command" 
AND ShmooTable."Hn [A/m]"="2" 
AND EmdTable."Time [ns]" IS NOT NULL 
AND EmdTable."Upper Sideband [mV]" IS NOT NULL)  
WHERE R0 IS NOT NULL AND R1 IS NOT NULL  GROUP BY R0

在 DB 浏览器中,大约需要 62 秒才能获得大约 15.000 个数据点的结果(对于 X 和 Y)

我的想法是立即在子查询中使用过滤条件,而不是将所有内容连接在一起并创建条件。 然后我的手动查询如下所示:

SELECT (R0), AVG(R1) FROM 
(
(SELECT (EmdTable."Time [ns]") AS R0, (EmdTable."Upper Sideband [mV]" ) AS R1, (EmdTable."ResultID") AS ID1 FROM EmdTable) AS emdquery INNER JOIN
(
SELECT ID2 FROM
(SELECT ResultTable.ID AS ID2, ShmooID FROM ResultTable WHERE ResultTable."CommandName"="APDU: Get PO" AND ResultTable."Repetition"="1" AND ResultTable."StepName"="Command" ) AS resultquery INNER JOIN
(SELECT ShmooTable.ID FROM ShmooTable WHERE ShmooTable."Hn [A/m]" = "2") AS shmooquery ON resultquery.ShmooID = shmooquery.ID
) AS subquery ON emdquery.ID1 = subquery.ID2
)WHERE R0 IS NOT NULL AND R1 IS NOT NULL  GROUP BY R0

现在看:这只需要大约 60 秒...所以并不是我希望的性能改进。

但是,“子查询”本身(上面的大查询中的那个)只需要大约 15 毫秒,并且只返回 3 个值。 如果我现在直接使用这三个值从EmdTable查询我的结果,就像这样:

SELECT EmdTable."Time [ns]", AVG(EmdTable."Upper Sideband [mV]") FROM EmdTable 
WHERE (EmdTable.ResultID = 1102 OR EmdTable.ResultID = 4818 OR EmdTable.ResultID = 8510) AND EmdTable."Time [ns]" IS NOT NULL AND EmdTable."Upper Sideband [mV]" IS NOT NULL 
GROUP BY  EmdTable."Time [ns]"

与前两个查询相同的结果“仅”需要大约 40 秒。改善 20 秒……还不错。

这让我想到了实际的问题:

  1. 我可以先以编程方式(15 毫秒)查询子查询,然后 再次以编程方式将结果插入主查询, 这应该不会超过 40 秒,对吧?
  2. 还有其他方法可以直接使用 sql 来执行此操作吗?

【问题讨论】:

  • 也许你应该在你的表上建立一些索引。
  • 这就是问题所在......我对数据库本身没有任何影响
  • 1.4GB 并使用 SQLite?删除 SQLite 并安装 PostgreSQL,伙计。你现在需要大炮。
  • 再次:对数据库没有影响。另外:对于这个例子,我搜索了一个极端的数据库,正常使用较小的数据库
  • 如果您无法为那些特定的 SQLite 数据库添加索引,您可以将它们复制到您可以控制的版本中,以便创建索引吗?还是将数据复制到性能更好的 DBMS,比如 Postgres?

标签: c# sql performance sqlite subquery


【解决方案1】:

问题 1 的答案当然是肯定的,尤其是如果您可以使用 LINQ to SQL 之类的东西,那就很容易了。 LINQ 将方法 Contains 转换为 SQL 运算符 IN

在SQL中,你可以使用IN的子查询吗?

SELECT EmdTable."Time [ns]", AVG(EmdTable."Upper Sideband [mV]") FROM EmdTable 
WHERE EmdTable.ResultID IN (
    SELECT ResultTable."ID"
    FROM ResultTable, ShmooTable 
    WHERE ResultTable."ShmooID"=ShmooTable."ID" 
          AND ResultTable."CommandName"="APDU: Get PO" 
          AND ResultTable."Repetition"="1" 
          AND ResultTable."StepName"="Command" 
          AND ShmooTable."Hn [A/m]"="2"
)
AND EmdTable."Time [ns]" IS NOT NULL AND EmdTable."Upper Sideband [mV]" IS NOT NULL
GROUP BY  EmdTable."Time [ns]"

【讨论】:

  • 好的,同时我在某处读到,第二个问题的答案是否定的,因为您不能在 sqlite 中存储中间变量值。您能否确认这一点并将其包含在您的答案中?然后我会标记你的答案。谢谢!
  • @RolandDeschain 你能解释一下你是如何创建/发送 SQL 到数据库的吗?一般来说,您可以使用 SQLite 的参数化查询并传递以前的结果。
  • @RolandDeschain 另外,使用IN 的子查询的示例 SQL 查询会发生什么情况?
  • 抱歉,我走错了路。使用 IN 应该可以工作(我还没有能够测试它,但是阅读它并且它符合我正在寻找的东西)。我会测试一下,如果我可以通过这种方式提高速度,谢谢!
  • @RolandDeschain 我在 SQLite 优化器上找到了this article,将来可能会有用。特别是,可以使用CROSS JOIN 并通过控制评估顺序使您的原始查询工作。
猜你喜欢
  • 2019-12-29
  • 2017-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-26
  • 1970-01-01
相关资源
最近更新 更多