【问题标题】:SQL Server: Inline Table-Value UDF vs. Inline ViewSQL Server:内联表值 UDF 与内联视图
【发布时间】:2010-12-04 08:33:38
【问题描述】:

我正在使用一个医疗记录系统,该系统将数据存储在一个类似于电子表格的结构中——列标题中的日期/时间,每行第一列中的测量值(例如医生姓名、Rh、血型),和相交单元格中的值。基于此构造的报告通常需要显示 10 个或更多这些度量。

出于报告目的,数据集需要为每位患者提供一行、进行测量的日期/时间以及每次测量的一列。本质上,需要将结构旋转 90 度。

有一次,我实际上使用 SQL Server 的 PIVOT 功能来做到这一点。由于各种原因,这种方法显然行不通。我决定使用内联视图 (IV) 将数据转换为所需的格式。简化的查询类似于:

SELECT patient_id, 
       datetime, 
       m1.value AS physician_name, 
       m2.value AS blood_type, 
       m3.value AS rh
  FROM patient_table
INNER JOIN ( complex query here
              WHERE measure_id=1) m1...
INNER JOIN (complex query here
              WHERE measure_id=2) m2...
LEFT OUTER JOIN (complex query here
                 WHERE measure_id=3) m3...

如您所见,在某些情况下,这些 IV 用于限制结果数据集(INNER JOIN),在其他情况下,它们不限制数据集(LEFT OUTER JOIN)。但是,除了 measure_id 不同之外,每个度量的“复杂查询”部分基本相同。虽然这种方法有效,但它会导致相当大的 SQL 语句,限制重用,并使查询容易出错。

我的想法是用内联表值 UDF 替换“复杂查询”和 WHERE 子句。这将大大简化查询,减少错误并增加代码重用。我心中唯一的问题是性能。 UDF 方法会导致性能显着下降吗?它可能会改善问题吗?

感谢您的时间和考虑。

【问题讨论】:

    标签: sql sql-server tsql user-defined-functions


    【解决方案1】:

    正确定义的 TVF 不会带来任何问题。与视图或临时表和变量相比,您会发现许多关于实习爆破 TVF 的性能问题的声明。通常不理解的是 TVF 的行为与视图不同。视图定义被放入原始查询中,然后优化器将重新排列它认为合适的查询树(除非在索引视图上使用 NOEXPAND 子句)。 TVF 具有不同的语义,有时,特别是在更新数据时,这会导致 TVF 输出为haloween protection 假脱机。它有助于标记函数WITH SCHEMABINDING,参见Improving query plans with the SCHEMABINDING option on T-SQL UDFs

    理解确定性和精确函数的概念也很重要。尽管它们主要适用于标量值函数,但 TVF 也会受到影响。见User-Defined Function Design Guidelines

    【讨论】:

    • 哇,有不少细微差别。感谢您的洞察力。
    • 我相信一个 TVF,如果它是内联/非多语句,也会被优化器扩展。声明视图已扩展,但没有为 TVF 提及这一点似乎暗示了一些可能具有误导性的东西。也许更新此答案以提及这一点。不过我不是这方面的专家。
    【解决方案2】:

    由于您需要 SQL 字符串并且可能无法向系统添加视图或 UDF,因此您可能希望使用 WITH ... AS 将复杂查询限制在一个位置(至少对于此语句。 )。

    WITH complex(patientid, datetime, measure_id, value) AS
    (Select... Complex Query)
    SELECT patient_id
    ,        datetime
    ,        m1.value AS physician_name
    ,        m2.value AS blood_type
    ,        m3.value AS rh  
    FROM patient_table
    INNER JOIN (Select ,,,, From complex WHERE measure_id=1) m1...
    INNER JOIN (Select ,,,, From complex WHERE measure_id=2) m2...
    LEFT OUTER JOIN (Select ,,,, From complex WHERE measure_id=3) m3...
    

    【讨论】:

    • 假设“复杂查询”在没有 WHERE 子句的情况下返回 1,000,000 行(它没有,但有助于说明我的问题)。数据库是否会生成 1,000,000 行一次,从它中选择每个连接(在我的示例中为三个)。还是它在优化方面做得比这更好?我不认为我可以向它添加 INDEX 提示?我知道基础表没有很好地索引,我们的数据库不会添加任何非供应商定义的索引。
    • 公用表表达式(复杂)将被创建一次,在这种情况下会被调用多次。 SQL 服务器可能会优化多次调用同一个查询,但可能不会优化非常复杂的查询。您的 DBA 应在测试查询性能方面提供一些帮助。
    【解决方案3】:

    Sql Server 2005 答案: 您可以使用 temp/var 表来减少内联视图。这些性能问题是查询每次命中所需的临时插入,但如果结果集足够小,它们会有所帮助。您可以在 var 表上使用主键,在临时表上使用主键/索引。除了正常的相信之外,我发现了几篇文章表明两个 temp/var 表都存储在 temp db 中。

    UDF 函数,我们发现在复杂查询中有多层 udf 时性能较差,但会保持可用性。 确保为指定的各种条件正确创建函数。将用于内连接的那些,以及将用于左连接的那些。

    所以,一般来说。我们确实使用 UDF,但是当我们发现性能下降时,我们会移动查询以将 UDF 选择插入到 temp/var 表中并加入这些表。

    创建易于使用/维护的功能,并在需要的地方和时间应用性能增强。

    编辑:

    如果你需要为 Crystal 运行这个,并且你打算使用存储过程,是的,你可以在 SP 中执行 sql 语句到 temp/var 表。

    如果您要使用 SP,请告诉我。然后,Sql 还将根据需要缓存具有给定参数的 sp 计划。

    同样从之前使用水晶的经验来看,要避免的事情是在水晶中进行分组,可以在 SP 中完成,如果不需要,页码。和函数调用,如果这可以在服务器上处理。

    【讨论】:

    • 请原谅我的无知,但我可以在标准 SQL 语句中使用 temp/var 表吗?它需要在报告工具(Crystal Reports)中运行。我猜你的解决方案需要一个SP,对吧?如果没有,您能否进一步扩展这种方法?我们使用的是 SQL Server 2005。
    • 表变量可以添加到对数据库执行的 sql 中。您是在应用程序中使用 sql,还是在 Crystal 中使用 sql?
    • 来自 Crystal Reports 的 Command 对象——本质上是一个原始 SQL 语句。我注意到数据库驱动器(即 ODBC 或 OLEDB)对 SQL 的功能有影响。例如,我过去在 OLEDB 中使用 WITH 语句时遇到过问题,但在 ODBC 中没有。这可能会影响我使用更高级技术的能力。
    • 存储过程对 DBA 来说将是一个艰难的卖点。
    • 远程数据库调用可能很昂贵。原始 Crystal 调用可能会很昂贵。你的 DBA 给你留下的东西很少,让他们为一天 X-) 笑话管理电话怎么样。 K,数据库是数据仓库吗?数据是否会定期更新,或者可能每隔一段时间,每小时、每天更新一次?
    【解决方案4】:

    您还有第三种选择;传统的 VIEW(假设您有一个要加入的密钥)。理论上,这三个选项之间不应该存在性能差异,因为 SQL Server 应该相应地评估和优化计划。现实情况是,有时情况并不像我们希望的那样发生。

    传统视图的好处是您可以将其设为索引视图,并为 SQL Server 提供另一种性能辅助;但是,您只需要测试并查看即可。

    【讨论】:

    • 传统视图在此客户端上不起作用,因为 DBA 拒绝在数据库中包含太多非供应商定义的对象。因此,大多数查询都嵌入在每个报告中(我们使用的是 CR)。我想到 UDF 的原因是它们的模块化。困难的部分是向 DBA 推销这个想法......索引视图是否类似于 Oracle 的物化视图?
    • 好久没和Oracle打过交道了,不知道。但是,我要指出 UDF 是一个非供应商定义的对象,因此您可能会在此处遇到相同的回击。如果您仅限于修改对象,我相信 asstander 使用临时表或变量的答案可能是您最好的选择。顺便说一句,在处理供应商数据库时,我倾向于使用交叉链接表等创建辅助数据库。这样我就可以在他们的数据库之外拥有自定义代码;您可能希望在未来将其作为一种选择进行探索。
    • 索引视图与 Oracle 的物化视图相同。视图必须符合某些限制:msdn.microsoft.com/en-us/library/ms191432.aspx,并且只有企业版会考虑使用索引视图进行数据访问。标准版和更低版本必须通过添加 NOEXPAND 提示来明确强制使用 iindexed 视图,请参阅msdn.microsoft.com/en-us/library/ms181151.aspx
    • 你是对的,它也是一个 NVDO。我认为我可能能够获得其中一些而不是大量视图的批准。我们会看到...我可以在“直接”SQL 中使用临时表或变量吗?如果是这样,那对我来说就是新闻。我一直在 SP 和 UDF 中使用它们。辅助数据库也是一个好主意。显然,它会包含自定义对象,但是如何访问 NVD 对象呢?
    • 您是指供应商对象吗?像往常一样连接到自定义数据库,然后执行 SELECT * FROM VendorDB.dbo.Table 之类的操作?我误解你的问题了吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-17
    相关资源
    最近更新 更多