【问题标题】:Should I use complex SQL queries or process results in the application?我应该在应用程序中使用复杂的 SQL 查询还是处理结果?
【发布时间】:2016-05-23 23:21:57
【问题描述】:

我正在处理一个包含大量 SQL 查询的应用程序。它们是如此复杂,以至于当我理解完一个时,我已经忘记了这一切是如何开始的。

我想知道从数据库中提取更多数据并在我的代码中进行最终查询是否是一个好习惯,比如说,使用 Python。我疯了吗?会不会影响性能?

注意,结果也很大,我说的是其他人开发的生产中的 ERP。

【问题讨论】:

  • 取决于您使用的数据库、您要检索的数据量、数据库的处理量等。
  • 反问:“数据库擅长什么?”
  • 基本直觉告诉我们只查询需要的数据会更好。

标签: python sql performance


【解决方案1】:

让数据库弄清楚如何最好地检索您想要的信息,否则您将不得不在代码中复制 RDBMS 的功能,这将比您的 SQL 查询复杂得多。

另外,您将浪费时间将所有不需要的信息从数据库传输到您的应用程序,以便您可以在代码中过滤和处理它。

这一切都是真的,因为你说你正在处理大数据。

【讨论】:

  • 我可以看到你是绝对正确的,但不知何故,@Nivas 带来了三个级别或案例,其中绝对使用 SQL 会带来问题。我倾向于更喜欢开放的答案。谢谢,再一次,我认为你是对的。
【解决方案2】:

我会尽可能地在应用程序中包含业务逻辑。查询中复杂的业务逻辑难以维护。 (当我理解完一个我已经忘记了它是如何开始的)存储过程中的复杂逻辑是可以的。但是对于一个典型的 python 应用程序,你会希望你的业务逻辑在 python 中。

现在,数据库在处理数据方面比您的应用程序代码要好得多。因此,如果您的逻辑涉及大量数据,您可以使用数据库中的逻辑获得更好的性能。但这将适用于对大量数据进行操作的复杂报告、簿记操作等。对于这些类型的操作,您可能希望使用专门从事此类操作的存储过程或系统(用于报告的数据仓库)。

正常 OLTP 操作不涉及大量数据。数据库可能很大,但典型事务所需的数据(通常)只是其中很小的一部分。在大型数据库中查询可能会导致性能问题,但您可以通过多种方式对其进行优化(索引、全文搜索、冗余、汇总表...取决于您的实际问题)。

每个规则都有例外,但作为一般准则,请尝试在应用程序代码中包含您的业务逻辑。复杂逻辑的存储过程。一个单独的数据仓库或一组报告程序。

【讨论】:

    【解决方案3】:

    我的经验是你应该让数据库来做处理。这将比首先从数据库中检索所有数据并有一些代码来加入和过滤结果要快得多。

    这里最难的部分是记录您的查询,以便其他人(甚至您)在一段时间后查看它们就会明白发生了什么。我发现大多数数据库都允许在 SQL 中使用 cmets。有时在 /* 注释 */ 标记之间,有时用 --comment 注释一行。

    记录的查询可能如下所示

    select name, dateofbirth from (
    -- The next subquery will retrieve ....
        select ....
    ) SR /* SR SubResults */
    ....
    

    【讨论】:

      【解决方案4】:

      @Nivas 通常是正确的。

      这些都是很常见的模式

      1. 分工 - DBA 必须返回业务所需的所有数据,但他们只有一个数据库可供使用。开发人员可以与 DBA 合作以做得更好,但部门的责任使这几乎是不可能的。所以使用 SQL 来做的不仅仅是检索数据。

      2. 缺少较小的功能。是否可以使用工作表将大规模查询分解为更小的阶段?是的,但我知道新表需要大量批准的环境 - 只是编写了一个繁重的查询

      所以,一般来说,从数据库中获取数据——这就是数据库。但是,如果 SQL 查询太长,RDBMS 将难以优化,这可能意味着查询一次性跨越数据、业务逻辑甚至表示。

      我建议一种更明智的方法通常是将“获取数据”部分分离到存储过程或填充登台表的其他可控查询中。然后业务逻辑可以写成脚本语言,位于上面并控制存储过程。并且介绍在别处被留下。本质上,像 cognos 这样的解决方案无论如何都会尝试这样做。

      但是,如果您正在研究生产中的 ERP,那么上述限制和解决方案可能已经存在 - 您在与合适的人交谈吗?

      【讨论】:

        【解决方案5】:

        我的一个应用程序 (B) 使用 tempdb 将复杂查询拆分为批处理。另一个应用程序 (B) 使用复杂的查询而不使用它。

        App A 对于大型数据库更有效。

        但是要查看您的情况,您可以像这样执行 DMV 脚本:

        -- Get top total worker time queries for entire instance (Query 38) (Top Worker Time Queries)
        SELECT TOP(50) DB_NAME(t.[dbid]) AS [Database Name], t.[text] AS [Query Text],  
        qs.total_worker_time AS [Total Worker Time], qs.min_worker_time AS [Min Worker Time],
        qs.total_worker_time/qs.execution_count AS [Avg Worker Time], 
        qs.max_worker_time AS [Max Worker Time], qs.execution_count AS [Execution Count], 
        qs.total_elapsed_time/qs.execution_count AS [Avg Elapsed Time], 
        qs.total_logical_reads/qs.execution_count AS [Avg Logical Reads], 
        qs.total_physical_reads/qs.execution_count AS [Avg Physical Reads], 
        qp.query_plan AS [Query Plan], qs.creation_time AS [Creation Time]
        FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK)
        CROSS APPLY sys.dm_exec_sql_text(plan_handle) AS t 
        CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp 
        ORDER BY qs.total_worker_time DESC OPTION (RECOMPILE);
        

        然后您可以打开查询计划进行重度查询并尝试搜索以下内容:

        StatementOptmEarlyAbortReason="TimeOut" 或者 StatementOptmEarlyAbortReason="MemoryLimitExceeded"

        这些事实告诉你把复杂的查询拆分成batch+tempdb

        PS。它适用于没有索引/表扫描、缺少索引等的良好查询。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-03-13
          • 1970-01-01
          • 1970-01-01
          • 2011-05-06
          • 1970-01-01
          • 2010-12-29
          • 2020-10-31
          相关资源
          最近更新 更多