使用select union all vs View将视图转换为UDF - 性能

时间:2015-04-21 03:55:33

标签: sql sql-server sql-server-2008 sql-server-2012

我目前正在维护一个至少有10个遗留应用程序使用它的数据库。这真的是一个很长的故事,所以我不会详细介绍它。

在数据库中,我们有一个包含以下代码的视图:

CREATE VIEW [dbo].[vw_ViewControl]
AS
SELECT
    'CAX1' AS table_name,
    max(convert(datetime,txn_pDate)) AS curr_dt,
    (
        SELECT MAX(CONVERT(datetime,txn_pDate)) 
        FROM tbl_txn WITH(NOLOCK)
            WHERE CONVERT(datetime,txn_pDate) <
            (
                SELECT MAX(CONVERT(datetime,txn_pDate)) 
                FROM tbl_txn WITH(NOLOCK))
    ) AS prev_dt,
    MAX(DateCreated) AS final_updte
FROM tbl_txn WITH(NOLOCK) UNION ALL

SELECT
    'CAX2' AS table_name,
    max(convert(datetime,txn_pDate)) AS curr_dt,
    (
        SELECT MAX(CONVERT(datetime,txn_pDate)) 
        FROM tbl_txn WITH(NOLOCK)
            WHERE CONVERT(datetime,txn_pDate) <
            (
                SELECT MAX(CONVERT(datetime,txn_pDate)) 
                FROM tbl_txn WITH(NOLOCK))
    ) AS prev_dt,
    MAX(DateCreated) AS final_updte
FROM tbl_txn WITH(NOLOCK) UNION ALL

SELECT
    'CAX3' AS table_name,
    max(convert(datetime,txn_pDate)) AS curr_dt,
    (
        SELECT MAX(CONVERT(datetime,txn_pDate)) 
        FROM tbl_txn WITH(NOLOCK)
            WHERE CONVERT(datetime,txn_pDate) <
            (
                SELECT MAX(CONVERT(datetime,txn_pDate)) 
                FROM tbl_txn WITH(NOLOCK))
    ) AS prev_dt,
    MAX(DateCreated) AS final_updte
FROM tbl_txn WITH(NOLOCK) UNION ALL

SELECT
    'CAX4' AS table_name,
    max(convert(datetime,txn_pDate)) AS curr_dt,
    (
        SELECT MAX(CONVERT(datetime,txn_pDate)) 
        FROM tbl_txn WITH(NOLOCK)
            WHERE CONVERT(datetime,txn_pDate) <
            (
                SELECT MAX(CONVERT(datetime,txn_pDate)) 
                FROM tbl_txn WITH(NOLOCK))
    ) AS prev_dt,
    MAX(DateCreated) AS final_updte
FROM tbl_txn WITH(NOLOCK)

为了提高性能,我用这个替换了代码。

CREATE FUNCTION dbo.udf_vw_ViewControl()
RETURNS @M_Control TABLE 
(
    table_name varchar(15) not null,
    curr_dt datetime not null,
    prev_dt datetime not null,
    final_updte datetime not null
)
AS
BEGIN

    declare
        @curr_dt datetime,
        @prev_dt datetime,
        @final_updte datetime


    SELECT
        @curr_dt = max(convert(datetime,txn_pDate)),
        @final_updte = MAX(DateCreated)
    FROM
        tbl_txn WITH(NOLOCK)


    SELECT @prev_dt = MAX(CONVERT(datetime,txn_pDate)) 
    FROM
        tbl_txn WITH(NOLOCK)
    WHERE
        CONVERT(datetime,txn_pDate) < @curr_dt

    INSERT @M_Control VALUES( 'ACCOUNT', @curr_dt, @prev_dt, @final_updte )
    INSERT @M_Control VALUES( 'CARDHLDR', @curr_dt, @prev_dt, @final_updte )
    INSERT @M_Control VALUES( 'CUSTOMER', @curr_dt, @prev_dt, @final_updte )
    INSERT @M_Control VALUES( 'TRANSACTNS', @curr_dt, @prev_dt, @final_updte )

    RETURN
END
GO

--================== ALTER VIEW

ALTER VIEW [dbo].[vw_ViewControl]
    AS
SELECT 
    xControl.table_name
    , xControl.curr_dt 
    , xControl.prev_dt 
    , xControl.final_updte
FROM
    dbo.udf_vw_ViewControl() xControl

GO

在应用程序中使用的原始视图运行大约4-5分钟。使用UDF的更新视图在至少15分钟内出乎意料地慢得多。我期待更新的视图会更快,因为我已经删除了查询的冗余部分。

任何想法为什么?或者还有另一种方法会更快吗?

非常感谢。

2 个答案:

答案 0 :(得分:1)

从第一个视图中我看到了性能问题:

CONVERT(datetime,txn_pDate) < @curr_dt

因为convert索引即使存在也不使用 你能提供执行计划来产生另一个想法吗?

答案 1 :(得分:0)

弗拉基米尔在那里有钱我会在那个

上添加计算列和索引
ALTER TABLE tbl_txn ADD txn_pDate_Date AS 
    CASE WHEN ISDATE(txn_pDate) = 1 THEN CONVERT(DATETIME, txn_pDate) ELSE NULL END

然后,您可以索引计算列

CREATE INDEX IDX_tbl_txn_txn_pDate_Date ON dbo.tbl_txn (txn_pDate_Date)

然后更新原始视图以引用计算列,如果问题中包含所有相关信息,您应该看到改进