Using indexes when comparing datetimesHow does database indexing work?How to return only the Date from a SQL Server DateTime datatypeWhen should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?Should I use the datetime or timestamp data type in MySQL?Converting string into datetimeCompare two dates with JavaScriptWhat do Clustered and Non clustered index actually mean?DateTime2 vs DateTime in SQL Serverindexing datetime column on a very wide tableOptimal Index on datetime colum for queries on day

In the time of the mishna, were there Jewish cities without courts?

Pulling the rope with one hand is as heavy as with two hands?

How to replace the "space symbol" (squat-u) in listings?

How to set printing options as reverse order as default on 18.04

Multiple options for Pseudonyms

How to stop co-workers from teasing me because I know Russian?

How to back up a running remote server?

Do I have an "anti-research" personality?

Please, smoke with good manners

Packing rectangles: Does rotation ever help?

Phrase for the opposite of "foolproof"

Does jamais mean always or never in this context?

Why do computer-science majors learn calculus?

You look catfish vs You look like a catfish

Did Henry V’s archers at Agincourt fight with no pants / breeches on because of dysentery?

Can a creature tell when it has been affected by a Divination wizard's Portent?

How to set the font color of quantity objects (Version 11.3 vs version 12)?

Asahi Dry Black beer can

What's the metal clinking sound at the end of credits in Avengers: Endgame?

What does 「再々起」mean?

Confused by notation of atomic number Z and mass number A on periodic table of elements

Minimum value of 4 digit number divided by sum of its digits

Why does processed meat contain preservatives, while canned fish needs not?

Is it possible to Ready a spell to be cast just before the start of your next turn by having the trigger be an ally's attack?



Using indexes when comparing datetimes


How does database indexing work?How to return only the Date from a SQL Server DateTime datatypeWhen should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?Should I use the datetime or timestamp data type in MySQL?Converting string into datetimeCompare two dates with JavaScriptWhat do Clustered and Non clustered index actually mean?DateTime2 vs DateTime in SQL Serverindexing datetime column on a very wide tableOptimal Index on datetime colum for queries on day






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








1















I have two tables, both of which containing millions of rows of data.



tbl_one:
purchasedtm DATETIME,
userid INT,
totalcost INT

tbl_two:
id BIGINT,
eventdtm DATETIME,
anothercol INT


The first table has a clustered index on the first two columns: CLUSTERED INDEX tbl_one_idx ON(purchasedtm, userid)



The second one has a primary key on its ID column, and also a non-clustered index on the eventdtm column.



I want to run a query which looks for rows in which purchasedtm and eventdtm are on the same day.



Originally, I wrote my query as:



WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE)


But this was not going to use either of the two indexes.



Later, I changed my query to this:



WHERE tbl_one.purchasedtm >= CAST(tbl_two.eventdtm AS DATE)
AND tbl_one.purchasedtm < DATEADD(DAY, 1, CAST(tbl_two.eventdtm AS DATE))


This way, because only one side of the comparison is wrapped in a function, the other side can still use its index. Correct?



I also have some additional questions:



  • I can write the query the other way around too, i.e. keeping tbl_two.eventdtm untouched and wrapping tbl_one.purchasedtm in CAST(). Would that make a difference in performance?

  • If the answer to the previous question is yes is it because eventdtm has its own dedicated index, while looking up purcahsedtm would only be a partial index match?

  • Are there other factors I can take into consideration for deciding which of the two choices is better? (For example, if there are millions of rows in tbl_one but billions of rows in tbl_two, would that impact which column I should CAST and which one I should not?)

  • In genera, if you compare two columns that are both indexed, would we gain any performance compared to a similar scenario in which only one of them is indexed?

  • And lastly, can I perform my original task without using CAST?

Note: I do not have the ability to create or modify indexes, add columns, etc.










share|improve this question



















  • 3





    WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE) "But this was not going to use either of the two indexes." Wrong. CAST([column] AS date) is SARGable/ SARGable functions in SQL Server

    – Larnu
    Mar 15 at 18:53







  • 1





    Ideally the userid would be a PK for table 1 and you'd have another table with all of the purchases. Are you joining these on the IT fields? If so, swapping the order of that clustered key would help.

    – scsimon
    Mar 15 at 18:53












  • Is your revised query using the index?

    – Salman A
    Mar 15 at 19:29











  • @Larnu I did not know that! Very interesting. I will read more and update my question. But can you respond to it in a non-SARGable context? (e.g. if I was using a CAST that was not SRGable, or a function other than CAST)

    – Merik
    Mar 18 at 2:18











  • Most of the time applying any function to a Column in your WHERE will make it non-SARGable. The only one I can think of is actually SARGable isCAST(column,AS date). I don't remember for sure off the top of my head, but I think CONVERT(int,DecimalColumn) is SARGable. The most common thing you (I) see are things like WHERE ISNULL(MyColumn,0) = ISNULL(@MyVariable,0) which isn't SARGable. Something like that would be better written using Boolean logic WHERE (MyColumn = @MyVariable OR (MyColumn IS NULL AND @MyVariable IS NULL)).

    – Larnu
    Mar 18 at 8:54


















1















I have two tables, both of which containing millions of rows of data.



tbl_one:
purchasedtm DATETIME,
userid INT,
totalcost INT

tbl_two:
id BIGINT,
eventdtm DATETIME,
anothercol INT


The first table has a clustered index on the first two columns: CLUSTERED INDEX tbl_one_idx ON(purchasedtm, userid)



The second one has a primary key on its ID column, and also a non-clustered index on the eventdtm column.



I want to run a query which looks for rows in which purchasedtm and eventdtm are on the same day.



Originally, I wrote my query as:



WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE)


But this was not going to use either of the two indexes.



Later, I changed my query to this:



WHERE tbl_one.purchasedtm >= CAST(tbl_two.eventdtm AS DATE)
AND tbl_one.purchasedtm < DATEADD(DAY, 1, CAST(tbl_two.eventdtm AS DATE))


This way, because only one side of the comparison is wrapped in a function, the other side can still use its index. Correct?



I also have some additional questions:



  • I can write the query the other way around too, i.e. keeping tbl_two.eventdtm untouched and wrapping tbl_one.purchasedtm in CAST(). Would that make a difference in performance?

  • If the answer to the previous question is yes is it because eventdtm has its own dedicated index, while looking up purcahsedtm would only be a partial index match?

  • Are there other factors I can take into consideration for deciding which of the two choices is better? (For example, if there are millions of rows in tbl_one but billions of rows in tbl_two, would that impact which column I should CAST and which one I should not?)

  • In genera, if you compare two columns that are both indexed, would we gain any performance compared to a similar scenario in which only one of them is indexed?

  • And lastly, can I perform my original task without using CAST?

Note: I do not have the ability to create or modify indexes, add columns, etc.










share|improve this question



















  • 3





    WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE) "But this was not going to use either of the two indexes." Wrong. CAST([column] AS date) is SARGable/ SARGable functions in SQL Server

    – Larnu
    Mar 15 at 18:53







  • 1





    Ideally the userid would be a PK for table 1 and you'd have another table with all of the purchases. Are you joining these on the IT fields? If so, swapping the order of that clustered key would help.

    – scsimon
    Mar 15 at 18:53












  • Is your revised query using the index?

    – Salman A
    Mar 15 at 19:29











  • @Larnu I did not know that! Very interesting. I will read more and update my question. But can you respond to it in a non-SARGable context? (e.g. if I was using a CAST that was not SRGable, or a function other than CAST)

    – Merik
    Mar 18 at 2:18











  • Most of the time applying any function to a Column in your WHERE will make it non-SARGable. The only one I can think of is actually SARGable isCAST(column,AS date). I don't remember for sure off the top of my head, but I think CONVERT(int,DecimalColumn) is SARGable. The most common thing you (I) see are things like WHERE ISNULL(MyColumn,0) = ISNULL(@MyVariable,0) which isn't SARGable. Something like that would be better written using Boolean logic WHERE (MyColumn = @MyVariable OR (MyColumn IS NULL AND @MyVariable IS NULL)).

    – Larnu
    Mar 18 at 8:54














1












1








1








I have two tables, both of which containing millions of rows of data.



tbl_one:
purchasedtm DATETIME,
userid INT,
totalcost INT

tbl_two:
id BIGINT,
eventdtm DATETIME,
anothercol INT


The first table has a clustered index on the first two columns: CLUSTERED INDEX tbl_one_idx ON(purchasedtm, userid)



The second one has a primary key on its ID column, and also a non-clustered index on the eventdtm column.



I want to run a query which looks for rows in which purchasedtm and eventdtm are on the same day.



Originally, I wrote my query as:



WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE)


But this was not going to use either of the two indexes.



Later, I changed my query to this:



WHERE tbl_one.purchasedtm >= CAST(tbl_two.eventdtm AS DATE)
AND tbl_one.purchasedtm < DATEADD(DAY, 1, CAST(tbl_two.eventdtm AS DATE))


This way, because only one side of the comparison is wrapped in a function, the other side can still use its index. Correct?



I also have some additional questions:



  • I can write the query the other way around too, i.e. keeping tbl_two.eventdtm untouched and wrapping tbl_one.purchasedtm in CAST(). Would that make a difference in performance?

  • If the answer to the previous question is yes is it because eventdtm has its own dedicated index, while looking up purcahsedtm would only be a partial index match?

  • Are there other factors I can take into consideration for deciding which of the two choices is better? (For example, if there are millions of rows in tbl_one but billions of rows in tbl_two, would that impact which column I should CAST and which one I should not?)

  • In genera, if you compare two columns that are both indexed, would we gain any performance compared to a similar scenario in which only one of them is indexed?

  • And lastly, can I perform my original task without using CAST?

Note: I do not have the ability to create or modify indexes, add columns, etc.










share|improve this question
















I have two tables, both of which containing millions of rows of data.



tbl_one:
purchasedtm DATETIME,
userid INT,
totalcost INT

tbl_two:
id BIGINT,
eventdtm DATETIME,
anothercol INT


The first table has a clustered index on the first two columns: CLUSTERED INDEX tbl_one_idx ON(purchasedtm, userid)



The second one has a primary key on its ID column, and also a non-clustered index on the eventdtm column.



I want to run a query which looks for rows in which purchasedtm and eventdtm are on the same day.



Originally, I wrote my query as:



WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE)


But this was not going to use either of the two indexes.



Later, I changed my query to this:



WHERE tbl_one.purchasedtm >= CAST(tbl_two.eventdtm AS DATE)
AND tbl_one.purchasedtm < DATEADD(DAY, 1, CAST(tbl_two.eventdtm AS DATE))


This way, because only one side of the comparison is wrapped in a function, the other side can still use its index. Correct?



I also have some additional questions:



  • I can write the query the other way around too, i.e. keeping tbl_two.eventdtm untouched and wrapping tbl_one.purchasedtm in CAST(). Would that make a difference in performance?

  • If the answer to the previous question is yes is it because eventdtm has its own dedicated index, while looking up purcahsedtm would only be a partial index match?

  • Are there other factors I can take into consideration for deciding which of the two choices is better? (For example, if there are millions of rows in tbl_one but billions of rows in tbl_two, would that impact which column I should CAST and which one I should not?)

  • In genera, if you compare two columns that are both indexed, would we gain any performance compared to a similar scenario in which only one of them is indexed?

  • And lastly, can I perform my original task without using CAST?

Note: I do not have the ability to create or modify indexes, add columns, etc.







sql-server datetime indexing casting sql-server-2016






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 18 at 2:14







Merik

















asked Mar 15 at 18:50









MerikMerik

1,23431327




1,23431327







  • 3





    WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE) "But this was not going to use either of the two indexes." Wrong. CAST([column] AS date) is SARGable/ SARGable functions in SQL Server

    – Larnu
    Mar 15 at 18:53







  • 1





    Ideally the userid would be a PK for table 1 and you'd have another table with all of the purchases. Are you joining these on the IT fields? If so, swapping the order of that clustered key would help.

    – scsimon
    Mar 15 at 18:53












  • Is your revised query using the index?

    – Salman A
    Mar 15 at 19:29











  • @Larnu I did not know that! Very interesting. I will read more and update my question. But can you respond to it in a non-SARGable context? (e.g. if I was using a CAST that was not SRGable, or a function other than CAST)

    – Merik
    Mar 18 at 2:18











  • Most of the time applying any function to a Column in your WHERE will make it non-SARGable. The only one I can think of is actually SARGable isCAST(column,AS date). I don't remember for sure off the top of my head, but I think CONVERT(int,DecimalColumn) is SARGable. The most common thing you (I) see are things like WHERE ISNULL(MyColumn,0) = ISNULL(@MyVariable,0) which isn't SARGable. Something like that would be better written using Boolean logic WHERE (MyColumn = @MyVariable OR (MyColumn IS NULL AND @MyVariable IS NULL)).

    – Larnu
    Mar 18 at 8:54













  • 3





    WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE) "But this was not going to use either of the two indexes." Wrong. CAST([column] AS date) is SARGable/ SARGable functions in SQL Server

    – Larnu
    Mar 15 at 18:53







  • 1





    Ideally the userid would be a PK for table 1 and you'd have another table with all of the purchases. Are you joining these on the IT fields? If so, swapping the order of that clustered key would help.

    – scsimon
    Mar 15 at 18:53












  • Is your revised query using the index?

    – Salman A
    Mar 15 at 19:29











  • @Larnu I did not know that! Very interesting. I will read more and update my question. But can you respond to it in a non-SARGable context? (e.g. if I was using a CAST that was not SRGable, or a function other than CAST)

    – Merik
    Mar 18 at 2:18











  • Most of the time applying any function to a Column in your WHERE will make it non-SARGable. The only one I can think of is actually SARGable isCAST(column,AS date). I don't remember for sure off the top of my head, but I think CONVERT(int,DecimalColumn) is SARGable. The most common thing you (I) see are things like WHERE ISNULL(MyColumn,0) = ISNULL(@MyVariable,0) which isn't SARGable. Something like that would be better written using Boolean logic WHERE (MyColumn = @MyVariable OR (MyColumn IS NULL AND @MyVariable IS NULL)).

    – Larnu
    Mar 18 at 8:54








3




3





WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE) "But this was not going to use either of the two indexes." Wrong. CAST([column] AS date) is SARGable/ SARGable functions in SQL Server

– Larnu
Mar 15 at 18:53






WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE) "But this was not going to use either of the two indexes." Wrong. CAST([column] AS date) is SARGable/ SARGable functions in SQL Server

– Larnu
Mar 15 at 18:53





1




1





Ideally the userid would be a PK for table 1 and you'd have another table with all of the purchases. Are you joining these on the IT fields? If so, swapping the order of that clustered key would help.

– scsimon
Mar 15 at 18:53






Ideally the userid would be a PK for table 1 and you'd have another table with all of the purchases. Are you joining these on the IT fields? If so, swapping the order of that clustered key would help.

– scsimon
Mar 15 at 18:53














Is your revised query using the index?

– Salman A
Mar 15 at 19:29





Is your revised query using the index?

– Salman A
Mar 15 at 19:29













@Larnu I did not know that! Very interesting. I will read more and update my question. But can you respond to it in a non-SARGable context? (e.g. if I was using a CAST that was not SRGable, or a function other than CAST)

– Merik
Mar 18 at 2:18





@Larnu I did not know that! Very interesting. I will read more and update my question. But can you respond to it in a non-SARGable context? (e.g. if I was using a CAST that was not SRGable, or a function other than CAST)

– Merik
Mar 18 at 2:18













Most of the time applying any function to a Column in your WHERE will make it non-SARGable. The only one I can think of is actually SARGable isCAST(column,AS date). I don't remember for sure off the top of my head, but I think CONVERT(int,DecimalColumn) is SARGable. The most common thing you (I) see are things like WHERE ISNULL(MyColumn,0) = ISNULL(@MyVariable,0) which isn't SARGable. Something like that would be better written using Boolean logic WHERE (MyColumn = @MyVariable OR (MyColumn IS NULL AND @MyVariable IS NULL)).

– Larnu
Mar 18 at 8:54






Most of the time applying any function to a Column in your WHERE will make it non-SARGable. The only one I can think of is actually SARGable isCAST(column,AS date). I don't remember for sure off the top of my head, but I think CONVERT(int,DecimalColumn) is SARGable. The most common thing you (I) see are things like WHERE ISNULL(MyColumn,0) = ISNULL(@MyVariable,0) which isn't SARGable. Something like that would be better written using Boolean logic WHERE (MyColumn = @MyVariable OR (MyColumn IS NULL AND @MyVariable IS NULL)).

– Larnu
Mar 18 at 8:54













2 Answers
2






active

oldest

votes


















0














Little. late after commenting but...



As discussed in the comments, code such as CAST(DateTimeColumn AS date) is actually SARGable. Rob Farley posted an article on some of the SARGable and non-SARGable functionality here, however, I'll cover a few things off anyway.



Firstly, applying a function to a column will normally make your query non-SARGable, and especially if it changes the order of the values or the order of them is meaningless. Take something like:



SELECT *
FROM TABLE
WHERE RIGHT(COLUMN,5) = 'value';


The order of the values in the column are utterly unhelpful here, as we're focusing on the right hand characters. Unfortunately, as Rob also discusses:



SELECT *
FROM TABLE
WHERE LEFT(COLUMN,5) = 'value';


This is also non-SARGable. However what about the following?



SELECT *
FROM TABLE
WHERE Column LIKE 'value%';


This is, as the logic isn't applied to the column and the order doesn't change. If the value wehre '%value%' then that too would be non-SARGable.



When applying logic that adds (or subtracts) what you want to find, you always want to apply that to the literal value (or function, like GETDATE()`). For example one of these expressions is SARGable the other is not:



Column + 1 = @Variable --non-SARGable
Column = @Variable - 1 --SARGable


The same applies to things like DATEADD



@DateVariable BETWEEN DateColumn AND DATEADD(DAY, 30,DateColumn) --non-SARGable
DateColumn BETWEEN DATEADD(DAY, -30, @DateVariable) AND @DateVariable --SARGable


Changing the datatype (other than to a date) rarely will keep a query SARGable. CONVERT(date,varchardate,112) will not be SARGable, even though the order of the column is unchanged. Converting an decimal to an int, however, had the same result as converting a datetime to a date, and kept SARGability:



CREATE TABLE testtab (n decimal(2,1) PRIMARY KEY CLUSTERED);
INSERT INTO testtab
VALUES(0.1),
(0.3),
(1.1),
(1.7),
(2.4);
GO

SELECT n
FROM testtab
WHERE CONVERT(int,n) = 2;
GO

DROP TABLE testtab;


enter image description here



Hopefully, that gives you enough to go on, but pelase do ask if you want me to add anything further.






share|improve this answer






























    0














    It is possible to create a persisted computed column in both tables that contains the date part only:



    purchasedt AS CAST(purchasedtm AS DATE)
    eventdt AS CAST(eventdtm AS DATE)


    And create an index on it.



    Regarding your original query: SQL Server can translate this:



    WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE)


    Into something similar to:



    WHERE tbl_one.purchasedtm BETWEEN -- first ms of tbl_two.eventdtm
    AND -- last ms of tbl_two.eventdtm


    But in your case (i) it will be have to calculate this for millions of rows inside tbl_two (ii) it will have to perform range scan inside a loop. SQL Server might not use the index.



    The indexed date column will result in an equality comparison and no conversion.






    share|improve this answer

























      Your Answer






      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "1"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













      draft saved

      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55189030%2fusing-indexes-when-comparing-datetimes%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      0














      Little. late after commenting but...



      As discussed in the comments, code such as CAST(DateTimeColumn AS date) is actually SARGable. Rob Farley posted an article on some of the SARGable and non-SARGable functionality here, however, I'll cover a few things off anyway.



      Firstly, applying a function to a column will normally make your query non-SARGable, and especially if it changes the order of the values or the order of them is meaningless. Take something like:



      SELECT *
      FROM TABLE
      WHERE RIGHT(COLUMN,5) = 'value';


      The order of the values in the column are utterly unhelpful here, as we're focusing on the right hand characters. Unfortunately, as Rob also discusses:



      SELECT *
      FROM TABLE
      WHERE LEFT(COLUMN,5) = 'value';


      This is also non-SARGable. However what about the following?



      SELECT *
      FROM TABLE
      WHERE Column LIKE 'value%';


      This is, as the logic isn't applied to the column and the order doesn't change. If the value wehre '%value%' then that too would be non-SARGable.



      When applying logic that adds (or subtracts) what you want to find, you always want to apply that to the literal value (or function, like GETDATE()`). For example one of these expressions is SARGable the other is not:



      Column + 1 = @Variable --non-SARGable
      Column = @Variable - 1 --SARGable


      The same applies to things like DATEADD



      @DateVariable BETWEEN DateColumn AND DATEADD(DAY, 30,DateColumn) --non-SARGable
      DateColumn BETWEEN DATEADD(DAY, -30, @DateVariable) AND @DateVariable --SARGable


      Changing the datatype (other than to a date) rarely will keep a query SARGable. CONVERT(date,varchardate,112) will not be SARGable, even though the order of the column is unchanged. Converting an decimal to an int, however, had the same result as converting a datetime to a date, and kept SARGability:



      CREATE TABLE testtab (n decimal(2,1) PRIMARY KEY CLUSTERED);
      INSERT INTO testtab
      VALUES(0.1),
      (0.3),
      (1.1),
      (1.7),
      (2.4);
      GO

      SELECT n
      FROM testtab
      WHERE CONVERT(int,n) = 2;
      GO

      DROP TABLE testtab;


      enter image description here



      Hopefully, that gives you enough to go on, but pelase do ask if you want me to add anything further.






      share|improve this answer



























        0














        Little. late after commenting but...



        As discussed in the comments, code such as CAST(DateTimeColumn AS date) is actually SARGable. Rob Farley posted an article on some of the SARGable and non-SARGable functionality here, however, I'll cover a few things off anyway.



        Firstly, applying a function to a column will normally make your query non-SARGable, and especially if it changes the order of the values or the order of them is meaningless. Take something like:



        SELECT *
        FROM TABLE
        WHERE RIGHT(COLUMN,5) = 'value';


        The order of the values in the column are utterly unhelpful here, as we're focusing on the right hand characters. Unfortunately, as Rob also discusses:



        SELECT *
        FROM TABLE
        WHERE LEFT(COLUMN,5) = 'value';


        This is also non-SARGable. However what about the following?



        SELECT *
        FROM TABLE
        WHERE Column LIKE 'value%';


        This is, as the logic isn't applied to the column and the order doesn't change. If the value wehre '%value%' then that too would be non-SARGable.



        When applying logic that adds (or subtracts) what you want to find, you always want to apply that to the literal value (or function, like GETDATE()`). For example one of these expressions is SARGable the other is not:



        Column + 1 = @Variable --non-SARGable
        Column = @Variable - 1 --SARGable


        The same applies to things like DATEADD



        @DateVariable BETWEEN DateColumn AND DATEADD(DAY, 30,DateColumn) --non-SARGable
        DateColumn BETWEEN DATEADD(DAY, -30, @DateVariable) AND @DateVariable --SARGable


        Changing the datatype (other than to a date) rarely will keep a query SARGable. CONVERT(date,varchardate,112) will not be SARGable, even though the order of the column is unchanged. Converting an decimal to an int, however, had the same result as converting a datetime to a date, and kept SARGability:



        CREATE TABLE testtab (n decimal(2,1) PRIMARY KEY CLUSTERED);
        INSERT INTO testtab
        VALUES(0.1),
        (0.3),
        (1.1),
        (1.7),
        (2.4);
        GO

        SELECT n
        FROM testtab
        WHERE CONVERT(int,n) = 2;
        GO

        DROP TABLE testtab;


        enter image description here



        Hopefully, that gives you enough to go on, but pelase do ask if you want me to add anything further.






        share|improve this answer

























          0












          0








          0







          Little. late after commenting but...



          As discussed in the comments, code such as CAST(DateTimeColumn AS date) is actually SARGable. Rob Farley posted an article on some of the SARGable and non-SARGable functionality here, however, I'll cover a few things off anyway.



          Firstly, applying a function to a column will normally make your query non-SARGable, and especially if it changes the order of the values or the order of them is meaningless. Take something like:



          SELECT *
          FROM TABLE
          WHERE RIGHT(COLUMN,5) = 'value';


          The order of the values in the column are utterly unhelpful here, as we're focusing on the right hand characters. Unfortunately, as Rob also discusses:



          SELECT *
          FROM TABLE
          WHERE LEFT(COLUMN,5) = 'value';


          This is also non-SARGable. However what about the following?



          SELECT *
          FROM TABLE
          WHERE Column LIKE 'value%';


          This is, as the logic isn't applied to the column and the order doesn't change. If the value wehre '%value%' then that too would be non-SARGable.



          When applying logic that adds (or subtracts) what you want to find, you always want to apply that to the literal value (or function, like GETDATE()`). For example one of these expressions is SARGable the other is not:



          Column + 1 = @Variable --non-SARGable
          Column = @Variable - 1 --SARGable


          The same applies to things like DATEADD



          @DateVariable BETWEEN DateColumn AND DATEADD(DAY, 30,DateColumn) --non-SARGable
          DateColumn BETWEEN DATEADD(DAY, -30, @DateVariable) AND @DateVariable --SARGable


          Changing the datatype (other than to a date) rarely will keep a query SARGable. CONVERT(date,varchardate,112) will not be SARGable, even though the order of the column is unchanged. Converting an decimal to an int, however, had the same result as converting a datetime to a date, and kept SARGability:



          CREATE TABLE testtab (n decimal(2,1) PRIMARY KEY CLUSTERED);
          INSERT INTO testtab
          VALUES(0.1),
          (0.3),
          (1.1),
          (1.7),
          (2.4);
          GO

          SELECT n
          FROM testtab
          WHERE CONVERT(int,n) = 2;
          GO

          DROP TABLE testtab;


          enter image description here



          Hopefully, that gives you enough to go on, but pelase do ask if you want me to add anything further.






          share|improve this answer













          Little. late after commenting but...



          As discussed in the comments, code such as CAST(DateTimeColumn AS date) is actually SARGable. Rob Farley posted an article on some of the SARGable and non-SARGable functionality here, however, I'll cover a few things off anyway.



          Firstly, applying a function to a column will normally make your query non-SARGable, and especially if it changes the order of the values or the order of them is meaningless. Take something like:



          SELECT *
          FROM TABLE
          WHERE RIGHT(COLUMN,5) = 'value';


          The order of the values in the column are utterly unhelpful here, as we're focusing on the right hand characters. Unfortunately, as Rob also discusses:



          SELECT *
          FROM TABLE
          WHERE LEFT(COLUMN,5) = 'value';


          This is also non-SARGable. However what about the following?



          SELECT *
          FROM TABLE
          WHERE Column LIKE 'value%';


          This is, as the logic isn't applied to the column and the order doesn't change. If the value wehre '%value%' then that too would be non-SARGable.



          When applying logic that adds (or subtracts) what you want to find, you always want to apply that to the literal value (or function, like GETDATE()`). For example one of these expressions is SARGable the other is not:



          Column + 1 = @Variable --non-SARGable
          Column = @Variable - 1 --SARGable


          The same applies to things like DATEADD



          @DateVariable BETWEEN DateColumn AND DATEADD(DAY, 30,DateColumn) --non-SARGable
          DateColumn BETWEEN DATEADD(DAY, -30, @DateVariable) AND @DateVariable --SARGable


          Changing the datatype (other than to a date) rarely will keep a query SARGable. CONVERT(date,varchardate,112) will not be SARGable, even though the order of the column is unchanged. Converting an decimal to an int, however, had the same result as converting a datetime to a date, and kept SARGability:



          CREATE TABLE testtab (n decimal(2,1) PRIMARY KEY CLUSTERED);
          INSERT INTO testtab
          VALUES(0.1),
          (0.3),
          (1.1),
          (1.7),
          (2.4);
          GO

          SELECT n
          FROM testtab
          WHERE CONVERT(int,n) = 2;
          GO

          DROP TABLE testtab;


          enter image description here



          Hopefully, that gives you enough to go on, but pelase do ask if you want me to add anything further.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Mar 22 at 19:14









          LarnuLarnu

          23.6k51933




          23.6k51933























              0














              It is possible to create a persisted computed column in both tables that contains the date part only:



              purchasedt AS CAST(purchasedtm AS DATE)
              eventdt AS CAST(eventdtm AS DATE)


              And create an index on it.



              Regarding your original query: SQL Server can translate this:



              WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE)


              Into something similar to:



              WHERE tbl_one.purchasedtm BETWEEN -- first ms of tbl_two.eventdtm
              AND -- last ms of tbl_two.eventdtm


              But in your case (i) it will be have to calculate this for millions of rows inside tbl_two (ii) it will have to perform range scan inside a loop. SQL Server might not use the index.



              The indexed date column will result in an equality comparison and no conversion.






              share|improve this answer





























                0














                It is possible to create a persisted computed column in both tables that contains the date part only:



                purchasedt AS CAST(purchasedtm AS DATE)
                eventdt AS CAST(eventdtm AS DATE)


                And create an index on it.



                Regarding your original query: SQL Server can translate this:



                WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE)


                Into something similar to:



                WHERE tbl_one.purchasedtm BETWEEN -- first ms of tbl_two.eventdtm
                AND -- last ms of tbl_two.eventdtm


                But in your case (i) it will be have to calculate this for millions of rows inside tbl_two (ii) it will have to perform range scan inside a loop. SQL Server might not use the index.



                The indexed date column will result in an equality comparison and no conversion.






                share|improve this answer



























                  0












                  0








                  0







                  It is possible to create a persisted computed column in both tables that contains the date part only:



                  purchasedt AS CAST(purchasedtm AS DATE)
                  eventdt AS CAST(eventdtm AS DATE)


                  And create an index on it.



                  Regarding your original query: SQL Server can translate this:



                  WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE)


                  Into something similar to:



                  WHERE tbl_one.purchasedtm BETWEEN -- first ms of tbl_two.eventdtm
                  AND -- last ms of tbl_two.eventdtm


                  But in your case (i) it will be have to calculate this for millions of rows inside tbl_two (ii) it will have to perform range scan inside a loop. SQL Server might not use the index.



                  The indexed date column will result in an equality comparison and no conversion.






                  share|improve this answer















                  It is possible to create a persisted computed column in both tables that contains the date part only:



                  purchasedt AS CAST(purchasedtm AS DATE)
                  eventdt AS CAST(eventdtm AS DATE)


                  And create an index on it.



                  Regarding your original query: SQL Server can translate this:



                  WHERE CAST(tbl_one.purchasedtm AS DATE) = CAST(tbl_two.eventdtm AS DATE)


                  Into something similar to:



                  WHERE tbl_one.purchasedtm BETWEEN -- first ms of tbl_two.eventdtm
                  AND -- last ms of tbl_two.eventdtm


                  But in your case (i) it will be have to calculate this for millions of rows inside tbl_two (ii) it will have to perform range scan inside a loop. SQL Server might not use the index.



                  The indexed date column will result in an equality comparison and no conversion.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Mar 15 at 21:14

























                  answered Mar 15 at 19:45









                  Salman ASalman A

                  187k68346444




                  187k68346444



























                      draft saved

                      draft discarded
















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55189030%2fusing-indexes-when-comparing-datetimes%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

                      Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

                      Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript