Eliminate key lookup in execution planHow (and why) does TOP impact an execution plan?Eliminate Key Lookup (Clustered) operator that slows down performanceWhy would optimiser choose Clustered Index + Sort instead of Non-Clustered Index?Key Lookup and Full-text indexKey lookup partition pruningSHOWPLAN does not display a warning but “Include Execution Plan” does for the same querydeteriorating stored procedure running timesComparison between A non-clustered primary key and a covering index in terms of performanceEliminate Key Lookup (Clustered) operator that slows down performanceCan't reduce cost of query plan and get rid of Key Lookup because of cursorCovering Index Changes Execution Plan but is not usedWhy does MSSQL choose scan in execution plan?

LWC: Is it safe to rely on window.location.href to get the page url?

I was reported to HR as being a satan worshiper

How to animate a function plot

Can UV radiation be safe for the skin?

Why is there no Disney logo in MCU movies?

Where should I draw the line on follow up questions from previous employer

What is a "hashed transaction" in SQL Server Replication terminology?

Can inductive kick be discharged without freewheeling diode, in this example?

“all of who” or “all of whom”?

Group riding etiquette

How were US credit cards verified in-store in the 1980's?

Moscow SVO airport, how to avoid scam taxis without pre-booking?

Necessity of tenure for lifetime academic research

math mode in ticks ( tikzpicture )

Which is the correct version of Mussorgsky's Pictures at an Exhibition?

What caused the end of cybernetic implants?

Why did I get UK entry stamps in my British passport?

Is the word 'mistake' a concrete or abstract noun?

Ask one verbal question to figure out who is blind and who is mute among three persons

Are sweatpants frowned upon on flights?

Under GDPR can I avoid divulging a customer's data to the government?

Can I leave a large suitcase at TPE during a 4-hour layover, and pick it up 4.5 days later when I come back to TPE on my way to Taipei downtown?

In what language did Túrin converse with Mím?

Cheap oscilloscope showing 16 MHz square wave



Eliminate key lookup in execution plan


How (and why) does TOP impact an execution plan?Eliminate Key Lookup (Clustered) operator that slows down performanceWhy would optimiser choose Clustered Index + Sort instead of Non-Clustered Index?Key Lookup and Full-text indexKey lookup partition pruningSHOWPLAN does not display a warning but “Include Execution Plan” does for the same querydeteriorating stored procedure running timesComparison between A non-clustered primary key and a covering index in terms of performanceEliminate Key Lookup (Clustered) operator that slows down performanceCan't reduce cost of query plan and get rid of Key Lookup because of cursorCovering Index Changes Execution Plan but is not usedWhy does MSSQL choose scan in execution plan?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








4















I have the following query:



DECLARE @p__linq__0 UNIQUEIDENTIFIER

SET @p__linq__0 = '... some guid ...'

SELECT TOP 1
[EventId] AS [EventId],
[DateCreated] AS [DateCreated],
[LocationId] AS [LocationId],
[SourceName] AS [SourceName],
[SourceState] AS [SourceState],
[Priority] AS [Priority],
[EventDescription] AS [EventDescription],
[FirstTrigger] AS [FirstTrigger]
FROM [dbo].[Watchdog]
WHERE
[LocationId] = @p__linq__0
AND
[FirstTrigger] = 1
ORDER BY [DateCreated] DESC


Watchdog table defines 2 indecies:



  1. Clustered index on EventId primary key column

  2. Unclustered index on DateCreated column

This is actual execution plan for the query:
enter image description here



Reading other posts on how to eliminate key lookup I added another non-clustered index which includes all columns from SELECT



CREATE NONCLUSTERED INDEX [LocationId_FirstTrigger] ON [dbo].[Watchdog]
(
[LocationId] ASC,
[FirstTrigger] ASC
)
INCLUDE ( [EventId],
[DateCreated],
[SourceName],
[SourceState],
[Priority],
[EventDescription]) WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]
GO


However, this didn't help and actual execution plan is the same. If I look at key lookup the output is actually included in newly added non clustered index.



enter image description here



My question is, why it's still doing key lookup instead of index scan/seek ?




UPDATE



Following some suggestions in the comments, I dropped newly created non clustered index & instead recreated non clustered index on DateCreated column including columns from SELECT.



Now execution plan is the following:



enter image description here



Also query execution time dropped from 1+ minute to few seconds (this table has 18+ million rows).



Does this mean key lookup was done due to ORDER BY on non-clustered index ?










share|improve this question





















  • 1





    Maybe a hint: dba.stackexchange.com/questions/222987/…

    – McNets
    10 hours ago

















4















I have the following query:



DECLARE @p__linq__0 UNIQUEIDENTIFIER

SET @p__linq__0 = '... some guid ...'

SELECT TOP 1
[EventId] AS [EventId],
[DateCreated] AS [DateCreated],
[LocationId] AS [LocationId],
[SourceName] AS [SourceName],
[SourceState] AS [SourceState],
[Priority] AS [Priority],
[EventDescription] AS [EventDescription],
[FirstTrigger] AS [FirstTrigger]
FROM [dbo].[Watchdog]
WHERE
[LocationId] = @p__linq__0
AND
[FirstTrigger] = 1
ORDER BY [DateCreated] DESC


Watchdog table defines 2 indecies:



  1. Clustered index on EventId primary key column

  2. Unclustered index on DateCreated column

This is actual execution plan for the query:
enter image description here



Reading other posts on how to eliminate key lookup I added another non-clustered index which includes all columns from SELECT



CREATE NONCLUSTERED INDEX [LocationId_FirstTrigger] ON [dbo].[Watchdog]
(
[LocationId] ASC,
[FirstTrigger] ASC
)
INCLUDE ( [EventId],
[DateCreated],
[SourceName],
[SourceState],
[Priority],
[EventDescription]) WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]
GO


However, this didn't help and actual execution plan is the same. If I look at key lookup the output is actually included in newly added non clustered index.



enter image description here



My question is, why it's still doing key lookup instead of index scan/seek ?




UPDATE



Following some suggestions in the comments, I dropped newly created non clustered index & instead recreated non clustered index on DateCreated column including columns from SELECT.



Now execution plan is the following:



enter image description here



Also query execution time dropped from 1+ minute to few seconds (this table has 18+ million rows).



Does this mean key lookup was done due to ORDER BY on non-clustered index ?










share|improve this question





















  • 1





    Maybe a hint: dba.stackexchange.com/questions/222987/…

    – McNets
    10 hours ago













4












4








4








I have the following query:



DECLARE @p__linq__0 UNIQUEIDENTIFIER

SET @p__linq__0 = '... some guid ...'

SELECT TOP 1
[EventId] AS [EventId],
[DateCreated] AS [DateCreated],
[LocationId] AS [LocationId],
[SourceName] AS [SourceName],
[SourceState] AS [SourceState],
[Priority] AS [Priority],
[EventDescription] AS [EventDescription],
[FirstTrigger] AS [FirstTrigger]
FROM [dbo].[Watchdog]
WHERE
[LocationId] = @p__linq__0
AND
[FirstTrigger] = 1
ORDER BY [DateCreated] DESC


Watchdog table defines 2 indecies:



  1. Clustered index on EventId primary key column

  2. Unclustered index on DateCreated column

This is actual execution plan for the query:
enter image description here



Reading other posts on how to eliminate key lookup I added another non-clustered index which includes all columns from SELECT



CREATE NONCLUSTERED INDEX [LocationId_FirstTrigger] ON [dbo].[Watchdog]
(
[LocationId] ASC,
[FirstTrigger] ASC
)
INCLUDE ( [EventId],
[DateCreated],
[SourceName],
[SourceState],
[Priority],
[EventDescription]) WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]
GO


However, this didn't help and actual execution plan is the same. If I look at key lookup the output is actually included in newly added non clustered index.



enter image description here



My question is, why it's still doing key lookup instead of index scan/seek ?




UPDATE



Following some suggestions in the comments, I dropped newly created non clustered index & instead recreated non clustered index on DateCreated column including columns from SELECT.



Now execution plan is the following:



enter image description here



Also query execution time dropped from 1+ minute to few seconds (this table has 18+ million rows).



Does this mean key lookup was done due to ORDER BY on non-clustered index ?










share|improve this question
















I have the following query:



DECLARE @p__linq__0 UNIQUEIDENTIFIER

SET @p__linq__0 = '... some guid ...'

SELECT TOP 1
[EventId] AS [EventId],
[DateCreated] AS [DateCreated],
[LocationId] AS [LocationId],
[SourceName] AS [SourceName],
[SourceState] AS [SourceState],
[Priority] AS [Priority],
[EventDescription] AS [EventDescription],
[FirstTrigger] AS [FirstTrigger]
FROM [dbo].[Watchdog]
WHERE
[LocationId] = @p__linq__0
AND
[FirstTrigger] = 1
ORDER BY [DateCreated] DESC


Watchdog table defines 2 indecies:



  1. Clustered index on EventId primary key column

  2. Unclustered index on DateCreated column

This is actual execution plan for the query:
enter image description here



Reading other posts on how to eliminate key lookup I added another non-clustered index which includes all columns from SELECT



CREATE NONCLUSTERED INDEX [LocationId_FirstTrigger] ON [dbo].[Watchdog]
(
[LocationId] ASC,
[FirstTrigger] ASC
)
INCLUDE ( [EventId],
[DateCreated],
[SourceName],
[SourceState],
[Priority],
[EventDescription]) WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]
GO


However, this didn't help and actual execution plan is the same. If I look at key lookup the output is actually included in newly added non clustered index.



enter image description here



My question is, why it's still doing key lookup instead of index scan/seek ?




UPDATE



Following some suggestions in the comments, I dropped newly created non clustered index & instead recreated non clustered index on DateCreated column including columns from SELECT.



Now execution plan is the following:



enter image description here



Also query execution time dropped from 1+ minute to few seconds (this table has 18+ million rows).



Does this mean key lookup was done due to ORDER BY on non-clustered index ?







sql-server sql-server-2012 query-performance execution-plan






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 10 hours ago







Michael

















asked 11 hours ago









MichaelMichael

1263 bronze badges




1263 bronze badges










  • 1





    Maybe a hint: dba.stackexchange.com/questions/222987/…

    – McNets
    10 hours ago












  • 1





    Maybe a hint: dba.stackexchange.com/questions/222987/…

    – McNets
    10 hours ago







1




1





Maybe a hint: dba.stackexchange.com/questions/222987/…

– McNets
10 hours ago





Maybe a hint: dba.stackexchange.com/questions/222987/…

– McNets
10 hours ago










2 Answers
2






active

oldest

votes


















4















You should move the column DateCreated to the key columns in the index LocationId_FirstTrigger.



Then you will get a seek on LocationId and FirstTrigger and a backward scan of the index to locate the row with highest value of DateCreated according to select top(1) ... order by DateCreated desc.



CREATE NONCLUSTERED INDEX [LocationId_FirstTrigger] ON [dbo].[Watchdog]
(
[LocationId] ASC,
[FirstTrigger] ASC,
[DateCreated]
)
INCLUDE (
[EventId],
[SourceName],
[SourceState],
[Priority],
[EventDescription]) WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]


If the index is not ordered by DateCreated SQL Server will have to read all matching rows and sort them to know what row to return.






share|improve this answer
































    4
















    My question is, why it's still doing key lookup instead of index scan/seek ?




    The query specifies that results should be ordered by DateCreated. Since you already had a nonclustered index on DateCreated, the optimizer decided that the cost of doing key lookups was lower than sorting all of the data by DateCreated.




    Does this mean key lookup was done due to ORDER BY on non-clustered index ?




    Essentially, yes. It was estimated to be cheaper* to read the data in the required order, and get any additional fields through a key lookup, rather than reading all of the fields from a single index and then sorting it by DateCreated.



    You could confirm this by comparing the estimated costs between



    • the original query (with the original indexes), and

    • the original query with an index hint

    The index hint would be like this on the FROM line:



    FROM [dbo].[Watchdog] WITH (INDEX (LocationId_FirstTrigger))


    This should produce a plan with no key lookups (since LocationId_FirstTrigger is covering for that query), and a Sort operator. I'd expect the "Estimated Cost" to be higher, thus the other plan was chosen.




    * To explain the optimizer's choice here:



    The TOP (1) in your query means the optimizer sets a row goal, meaning the plan is geared toward producing one row quickly. The optimizer expects to find one row from the Index Scan matching your LocationId predicate very quickly, since it assumes values are distributed uniformly. This may or may not be true in reality. The cost of one Key Lookup following the Index Scan is pretty small.



    The scan + lookup option therefore looks cheaper to the optimizer than finding matches using LocationId_FirstTrigger and sorting. You can turn the row goal logic off for the query as a test by adding an OPTION (QUERYTRACEON 4138) hint. You will likely find the optimizer then chooses the LocationId_FirstTrigger index without an index hint.



    Still, the best alternative is to modify your index as Mikael Eriksson suggests.






    share|improve this answer





























      Your Answer








      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "182"
      ;
      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: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      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%2fdba.stackexchange.com%2fquestions%2f246649%2feliminate-key-lookup-in-execution-plan%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









      4















      You should move the column DateCreated to the key columns in the index LocationId_FirstTrigger.



      Then you will get a seek on LocationId and FirstTrigger and a backward scan of the index to locate the row with highest value of DateCreated according to select top(1) ... order by DateCreated desc.



      CREATE NONCLUSTERED INDEX [LocationId_FirstTrigger] ON [dbo].[Watchdog]
      (
      [LocationId] ASC,
      [FirstTrigger] ASC,
      [DateCreated]
      )
      INCLUDE (
      [EventId],
      [SourceName],
      [SourceState],
      [Priority],
      [EventDescription]) WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]


      If the index is not ordered by DateCreated SQL Server will have to read all matching rows and sort them to know what row to return.






      share|improve this answer





























        4















        You should move the column DateCreated to the key columns in the index LocationId_FirstTrigger.



        Then you will get a seek on LocationId and FirstTrigger and a backward scan of the index to locate the row with highest value of DateCreated according to select top(1) ... order by DateCreated desc.



        CREATE NONCLUSTERED INDEX [LocationId_FirstTrigger] ON [dbo].[Watchdog]
        (
        [LocationId] ASC,
        [FirstTrigger] ASC,
        [DateCreated]
        )
        INCLUDE (
        [EventId],
        [SourceName],
        [SourceState],
        [Priority],
        [EventDescription]) WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]


        If the index is not ordered by DateCreated SQL Server will have to read all matching rows and sort them to know what row to return.






        share|improve this answer



























          4














          4










          4









          You should move the column DateCreated to the key columns in the index LocationId_FirstTrigger.



          Then you will get a seek on LocationId and FirstTrigger and a backward scan of the index to locate the row with highest value of DateCreated according to select top(1) ... order by DateCreated desc.



          CREATE NONCLUSTERED INDEX [LocationId_FirstTrigger] ON [dbo].[Watchdog]
          (
          [LocationId] ASC,
          [FirstTrigger] ASC,
          [DateCreated]
          )
          INCLUDE (
          [EventId],
          [SourceName],
          [SourceState],
          [Priority],
          [EventDescription]) WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]


          If the index is not ordered by DateCreated SQL Server will have to read all matching rows and sort them to know what row to return.






          share|improve this answer













          You should move the column DateCreated to the key columns in the index LocationId_FirstTrigger.



          Then you will get a seek on LocationId and FirstTrigger and a backward scan of the index to locate the row with highest value of DateCreated according to select top(1) ... order by DateCreated desc.



          CREATE NONCLUSTERED INDEX [LocationId_FirstTrigger] ON [dbo].[Watchdog]
          (
          [LocationId] ASC,
          [FirstTrigger] ASC,
          [DateCreated]
          )
          INCLUDE (
          [EventId],
          [SourceName],
          [SourceState],
          [Priority],
          [EventDescription]) WITH (STATISTICS_NORECOMPUTE = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]


          If the index is not ordered by DateCreated SQL Server will have to read all matching rows and sort them to know what row to return.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered 8 hours ago









          Mikael ErikssonMikael Eriksson

          19k3 gold badges47 silver badges89 bronze badges




          19k3 gold badges47 silver badges89 bronze badges


























              4
















              My question is, why it's still doing key lookup instead of index scan/seek ?




              The query specifies that results should be ordered by DateCreated. Since you already had a nonclustered index on DateCreated, the optimizer decided that the cost of doing key lookups was lower than sorting all of the data by DateCreated.




              Does this mean key lookup was done due to ORDER BY on non-clustered index ?




              Essentially, yes. It was estimated to be cheaper* to read the data in the required order, and get any additional fields through a key lookup, rather than reading all of the fields from a single index and then sorting it by DateCreated.



              You could confirm this by comparing the estimated costs between



              • the original query (with the original indexes), and

              • the original query with an index hint

              The index hint would be like this on the FROM line:



              FROM [dbo].[Watchdog] WITH (INDEX (LocationId_FirstTrigger))


              This should produce a plan with no key lookups (since LocationId_FirstTrigger is covering for that query), and a Sort operator. I'd expect the "Estimated Cost" to be higher, thus the other plan was chosen.




              * To explain the optimizer's choice here:



              The TOP (1) in your query means the optimizer sets a row goal, meaning the plan is geared toward producing one row quickly. The optimizer expects to find one row from the Index Scan matching your LocationId predicate very quickly, since it assumes values are distributed uniformly. This may or may not be true in reality. The cost of one Key Lookup following the Index Scan is pretty small.



              The scan + lookup option therefore looks cheaper to the optimizer than finding matches using LocationId_FirstTrigger and sorting. You can turn the row goal logic off for the query as a test by adding an OPTION (QUERYTRACEON 4138) hint. You will likely find the optimizer then chooses the LocationId_FirstTrigger index without an index hint.



              Still, the best alternative is to modify your index as Mikael Eriksson suggests.






              share|improve this answer































                4
















                My question is, why it's still doing key lookup instead of index scan/seek ?




                The query specifies that results should be ordered by DateCreated. Since you already had a nonclustered index on DateCreated, the optimizer decided that the cost of doing key lookups was lower than sorting all of the data by DateCreated.




                Does this mean key lookup was done due to ORDER BY on non-clustered index ?




                Essentially, yes. It was estimated to be cheaper* to read the data in the required order, and get any additional fields through a key lookup, rather than reading all of the fields from a single index and then sorting it by DateCreated.



                You could confirm this by comparing the estimated costs between



                • the original query (with the original indexes), and

                • the original query with an index hint

                The index hint would be like this on the FROM line:



                FROM [dbo].[Watchdog] WITH (INDEX (LocationId_FirstTrigger))


                This should produce a plan with no key lookups (since LocationId_FirstTrigger is covering for that query), and a Sort operator. I'd expect the "Estimated Cost" to be higher, thus the other plan was chosen.




                * To explain the optimizer's choice here:



                The TOP (1) in your query means the optimizer sets a row goal, meaning the plan is geared toward producing one row quickly. The optimizer expects to find one row from the Index Scan matching your LocationId predicate very quickly, since it assumes values are distributed uniformly. This may or may not be true in reality. The cost of one Key Lookup following the Index Scan is pretty small.



                The scan + lookup option therefore looks cheaper to the optimizer than finding matches using LocationId_FirstTrigger and sorting. You can turn the row goal logic off for the query as a test by adding an OPTION (QUERYTRACEON 4138) hint. You will likely find the optimizer then chooses the LocationId_FirstTrigger index without an index hint.



                Still, the best alternative is to modify your index as Mikael Eriksson suggests.






                share|improve this answer





























                  4














                  4










                  4










                  My question is, why it's still doing key lookup instead of index scan/seek ?




                  The query specifies that results should be ordered by DateCreated. Since you already had a nonclustered index on DateCreated, the optimizer decided that the cost of doing key lookups was lower than sorting all of the data by DateCreated.




                  Does this mean key lookup was done due to ORDER BY on non-clustered index ?




                  Essentially, yes. It was estimated to be cheaper* to read the data in the required order, and get any additional fields through a key lookup, rather than reading all of the fields from a single index and then sorting it by DateCreated.



                  You could confirm this by comparing the estimated costs between



                  • the original query (with the original indexes), and

                  • the original query with an index hint

                  The index hint would be like this on the FROM line:



                  FROM [dbo].[Watchdog] WITH (INDEX (LocationId_FirstTrigger))


                  This should produce a plan with no key lookups (since LocationId_FirstTrigger is covering for that query), and a Sort operator. I'd expect the "Estimated Cost" to be higher, thus the other plan was chosen.




                  * To explain the optimizer's choice here:



                  The TOP (1) in your query means the optimizer sets a row goal, meaning the plan is geared toward producing one row quickly. The optimizer expects to find one row from the Index Scan matching your LocationId predicate very quickly, since it assumes values are distributed uniformly. This may or may not be true in reality. The cost of one Key Lookup following the Index Scan is pretty small.



                  The scan + lookup option therefore looks cheaper to the optimizer than finding matches using LocationId_FirstTrigger and sorting. You can turn the row goal logic off for the query as a test by adding an OPTION (QUERYTRACEON 4138) hint. You will likely find the optimizer then chooses the LocationId_FirstTrigger index without an index hint.



                  Still, the best alternative is to modify your index as Mikael Eriksson suggests.






                  share|improve this answer
















                  My question is, why it's still doing key lookup instead of index scan/seek ?




                  The query specifies that results should be ordered by DateCreated. Since you already had a nonclustered index on DateCreated, the optimizer decided that the cost of doing key lookups was lower than sorting all of the data by DateCreated.




                  Does this mean key lookup was done due to ORDER BY on non-clustered index ?




                  Essentially, yes. It was estimated to be cheaper* to read the data in the required order, and get any additional fields through a key lookup, rather than reading all of the fields from a single index and then sorting it by DateCreated.



                  You could confirm this by comparing the estimated costs between



                  • the original query (with the original indexes), and

                  • the original query with an index hint

                  The index hint would be like this on the FROM line:



                  FROM [dbo].[Watchdog] WITH (INDEX (LocationId_FirstTrigger))


                  This should produce a plan with no key lookups (since LocationId_FirstTrigger is covering for that query), and a Sort operator. I'd expect the "Estimated Cost" to be higher, thus the other plan was chosen.




                  * To explain the optimizer's choice here:



                  The TOP (1) in your query means the optimizer sets a row goal, meaning the plan is geared toward producing one row quickly. The optimizer expects to find one row from the Index Scan matching your LocationId predicate very quickly, since it assumes values are distributed uniformly. This may or may not be true in reality. The cost of one Key Lookup following the Index Scan is pretty small.



                  The scan + lookup option therefore looks cheaper to the optimizer than finding matches using LocationId_FirstTrigger and sorting. You can turn the row goal logic off for the query as a test by adding an OPTION (QUERYTRACEON 4138) hint. You will likely find the optimizer then chooses the LocationId_FirstTrigger index without an index hint.



                  Still, the best alternative is to modify your index as Mikael Eriksson suggests.







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited 7 hours ago









                  Paul White

                  58.8k16 gold badges307 silver badges484 bronze badges




                  58.8k16 gold badges307 silver badges484 bronze badges










                  answered 9 hours ago









                  Josh DarnellJosh Darnell

                  12.1k3 gold badges27 silver badges60 bronze badges




                  12.1k3 gold badges27 silver badges60 bronze badges






























                      draft saved

                      draft discarded
















































                      Thanks for contributing an answer to Database Administrators Stack Exchange!


                      • 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%2fdba.stackexchange.com%2fquestions%2f246649%2feliminate-key-lookup-in-execution-plan%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

                      Canceling a color specificationRandomly assigning color to Graphics3D objects?Default color for Filling in Mathematica 9Coloring specific elements of sets with a prime modified order in an array plotHow to pick a color differing significantly from the colors already in a given color list?Detection of the text colorColor numbers based on their valueCan color schemes for use with ColorData include opacity specification?My dynamic color schemes

                      Invision Community Contents History See also References External links Navigation menuProprietaryinvisioncommunity.comIPS Community ForumsIPS Community Forumsthis blog entry"License Changes, IP.Board 3.4, and the Future""Interview -- Matt Mecham of Ibforums""CEO Invision Power Board, Matt Mecham Is a Liar, Thief!"IPB License Explanation 1.3, 1.3.1, 2.0, and 2.1ArchivedSecurity Fixes, Updates And Enhancements For IPB 1.3.1Archived"New Demo Accounts - Invision Power Services"the original"New Default Skin"the original"Invision Power Board 3.0.0 and Applications Released"the original"Archived copy"the original"Perpetual licenses being done away with""Release Notes - Invision Power Services""Introducing: IPS Community Suite 4!"Invision Community Release Notes

                      199年 目錄 大件事 到箇年出世嗰人 到箇年死嗰人 節慶、風俗習慣 導覽選單