How to make repeating custom expressions in SQL queries maintainable

天大地大妈咪最大 提交于 2021-02-18 17:50:06

问题


Imagine the following simple query, where I get a list of all users that were created within the last 3 days, the logic or example is not important

SELECT
    ...
    , DATEDIFF(DAY, U.DateCreated, GETUTCDATE())
    ...
FROM
    dbo.AspNetUsers U
WHERE
    DATEDIFF(DAY, U.DateCreated, GETUTCDATE()) < 3

I've repeated some code DATEDIFF(DAY, U.DateCreated, GETUTCDATE()) < 3 which, when I have much more complicated examples of the above I don't want to maintain twice or however many times I need that logic.

How should one go about dealing with this with performance in mind?

Thanks


回答1:


If you have performance in mind, then you'd better repeat expressions when needed. Specifically, don't try to put them in a user-defined functions. They are known to make queries slow in SQL Server.

Having said that, there are at least two methods in SQL Server to make queries more readable without affecting the performance:

  1. CTE
  2. CROSS APPLY

Example for use of CTE:

WITH
CTE
AS
(

    SELECT
        ...
        , DATEDIFF(DAY, U.DateCreated, GETUTCDATE()) AS CalculatedColumn
        ...
    FROM
        dbo.AspNetUsers U

)
SELECT
    ...
    CalculatedColumn
    ...
FROM CTE
WHERE
    CalculatedColumn < 3
;

Example for using CROSS APPLY:

Instead of repeating parts of the formula in the following query:

SELECT
    ColA + ColB AS ColSum
    ,ColA - ColB AS ColDiff
    ,(ColA + ColB) * (ColA - ColB) AS Result
    ,(ColA + ColB) * (ColA - ColB) * 100.0 AS Percentage
FROM Table

You can use CROSS APPLY to write it like this:

SELECT
    ColSum
    ,ColDiff
    ,Result
    ,Result * 100.0 AS Percentage
FROM
    Table
    CROSS APPLY
    (
        SELECT
            ColA + ColB AS ColSum
            ,ColA - ColB AS ColDiff
    ) AS A1
    CROSS APPLY
    (
        SELECT ColSum * ColDiff AS Result
    ) AS A2

By the way, speaking about performance,

WHERE DATEDIFF(DAY, U.DateCreated, GETUTCDATE()) < 3

is terrible, because it can't use index on DateCreated (because you wrapped the column in a function).

You'd better rewrite it as something like

WHERE U.DateCreated > DATEADD(DAY, -3, GETUTCDATE())



回答2:


I would use CROSS APPLY with VALUES:

SELECT . . ., v.diff
FROM dbo.AspNetUsers U CROSS APPLY
     (VALUES (DATEDIFF(DAY, U.DateCreated, GETUTCDATE()))
     ) v(diff)
WHERE v.diff < 3;

You can add multiple expressions to the values clause:

SELECT . . ., v.diff
FROM dbo.AspNetUsers U CROSS APPLY
     (VALUES (DATEDIFF(DAY, U.DateCreated, GETUTCDATE()),
              YEAR(U.DateCreated)
             )
     ) v(diff, yyyy)
WHERE v.diff < 3;



回答3:


Similar approach to Gordon Linoff's, but using a SELECT subquery:

SELECT . . ., v.diff
FROM dbo.AspNetUsers U CROSS APPLY
     (SELECT DATEDIFF(DAY, U.DateCreated, GETUTCDATE()) as diff
     ) v
WHERE v.diff < 3;



回答4:


In this clause WHERE DATEDIFF(DAY, U.DateCreated, GETUTCDATE()) < 3, Index will not get seeked. so you need to apply where clause with, WHERE U.DateCreated >= DATEADD(DAY, -3, GETUTCDATE()).

Now, Your index over U.DateCreated will get seek and better performs. and now you can use DATETIFF type of functions in SELECT Statement.



来源:https://stackoverflow.com/questions/54993580/how-to-make-repeating-custom-expressions-in-sql-queries-maintainable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!