Bad query plan for self-referencing CTE view query and variable in WHERE clause. Is there way out or this is SQL Server defect?
Please help. Thank you for your time and expertise.
Prerequisites: sql query needs to be a view. Real view is more than recursion. It computes location path, is used in JOINs and returns this path.
Problem: no matter what I tried, sql server does not produce 'index seek' when using variable but does with literal.
See full reproduction code below.
I expect that query SELECT lcCode FROM dbo.vwLocationCodes l WHERE l.lcID = @lcID will seek UNIQUE index but it does not.
I tried these:
1. Changing UX and/or PK to be CLUSTERED.
2. query OPTION(RECOMPILE)
3. FORCESEEK on view
4. SQL Server 2012/2014
5. Wrap it into function and CROSS APPLY. On large outer number of rows this just dies, no solution
but to no avail. This smells like a bug in SQL Server. I am seeking your confirmation.
I am thinking it is a bug as variable value is high-cardinality, 1, and query is against unique key. This must produce single seek, depending if clustered or nonclustred index is unique
Thanks
Vladimir
use tempdb
BEGIN TRAN
-- setup definition
CREATE TABLE dbo.LocationHierarchy(
lcID int NOT NULL ,
lcHID hierarchyid NOT NULL,
lcCode nvarchar(25) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
lcHIDParent AS lcHID.GetAncestor(1) PERSISTED,
CONSTRAINT PK_LocationHierarchy_lcID PRIMARY KEY NONCLUSTERED (lcID ASC),
CONSTRAINT UX_LocationHierarchy_pltID_lcHID UNIQUE CLUSTERED (lcHID ASC)
-- add some data
INSERT INTO dbo.LocationHierarchy
VALUES
(1, '/', 'A')
,(2, '/1/', 'B')
,(3, '/1/1/', 'C')
,(4, '/1/1/1/', 'D')
--DROP VIEW dbo.vwLocationCodes
GO
CREATE VIEW dbo.vwLocationCodes
AS
WITH ru AS
SELECT
lh.lcID
,lh.lcCode
,lh.lcHID
,CAST('/' + lh.lcCode + '/' as varchar(8000)) as LocationPath
-- to support recursion
,lh.lcHIDParent
FROM dbo.LocationHierarchy lh
UNION ALL
SELECT
ru.lcID
,ru.lcCode
,ru.lcHID
,CAST('/' + lh.lcCode + ru.LocationPath as varchar(8000)) as LocationPath
,lh.lcHIDParent
FROM dbo.LocationHierarchy lh
JOIN ru ON ru.lcHIDParent = lh.lcHID
SELECT
lh.lcID
,lh.lcCode
,lh.LocationPath
,lh.lcHID
FROM ru lh
WHERE lh.lcHIDParent IS NULL
GO
-- get data via view
SELECT
CONCAT(SPACE(l.lcHID.GetLevel() * 4), lcCode) as LocationIndented
FROM dbo.vwLocationCodes l
ORDER BY lcHID
GO
SET SHOWPLAN_XML ON
GO
DECLARE @lcID int = 2
-- I believe this produces bad plan and is defect in SQL Server optimizer.
-- variable value cardinality is 1 and SQL Server should know that. Optiomal plan is to do index seek with key lookup.
-- This does not happen.
SELECT lcCode FROM dbo.vwLocationCodes l WHERE l.lcID = @lcID -- bad plan
-- this is a plan I expect.
SELECT lcCode FROM dbo.vwLocationCodes l WHERE l.lcID = 2 -- good plan
-- I reviewed these but I need a view here, can't be SP
-- http://sqlblogcasts.com/blogs/tonyrogerson/archive/2008/05/17/non-recursive-common-table-expressions-performance-sucks-1-cte-self-join-cte-sub-query-inline-expansion.aspx
-- http://social.msdn.microsoft.com/Forums/sqlserver/en-US/22d2d580-0ff8-4a9b-b0d0-e6a8345062df/issue-with-select-using-a-recursive-cte-and-parameterizing-the-query?forum=transactsql
GO
SET SHOWPLAN_XML OFF
GO
ROLLBACK
Vladimir Moldovanenko
Here is more... note that I am creating table Items and these can be in Locations.
I am trying LEFT JOIN and OUTER APLLY to 'bend' query into NESTED LOOP and SEEK. There has to be nested loop, 2 rows against 4. But SQL Server fails to generate optimal plan with SEEK. Even RECOMPILE does not help
use tempdb
BEGIN TRAN
-- setup definition
CREATE TABLE dbo.LocationHierarchy(
lcID int NOT NULL ,
lcHID hierarchyid NOT NULL,
lcCode nvarchar(25) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
lcHIDParent AS lcHID.GetAncestor(1) PERSISTED,
CONSTRAINT PK_LocationHierarchy_lcID PRIMARY KEY NONCLUSTERED (lcID ASC),
CONSTRAINT UX_LocationHierarchy_pltID_lcHID UNIQUE CLUSTERED (lcHID ASC)
-- add some data
INSERT INTO dbo.LocationHierarchy
VALUES
(1, '/', 'A')
,(2, '/1/', 'B')
,(3, '/1/1/', 'C')
,(4, '/1/1/1/', 'D')
--DROP VIEW dbo.vwLocationCodes
GO
--DECLARE @Count int = 10;
--WITH L0 AS (SELECT N FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N (N))-- 10 rows
--,L1 AS (SELECT n1.N FROM L0 n1 CROSS JOIN L0 n2) -- 100 rows
--,L2 AS (SELECT n1.N FROM L1 n1 CROSS JOIN L1 n2) -- 10,000 rows
--,L3 AS (SELECT n1.N FROM L2 n1 CROSS JOIN L2 n2) -- 100,000,000 rows
--,x AS
-- SELECT TOP (ISNULL(@Count, 0))
-- ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) as Number
-- FROM L3 n1
--SELECT Number as itmID, NTILE(4)OVER(ORDER BY Number) as lcID
--INTO dbo.Items
--FROM x
----ORDER BY n1.N
--ALTER TABLE dbo.Items ALTER COLUMN itmID INT NOT NULL
--ALTER TABLE dbo.Items ADD CONSTRAINT PK PRIMARY KEY CLUSTERED (itmID)
CREATE TABLE dbo.Items (itmID int NOT NULL PRIMARY KEY, lcID int NOT NULL)
INSERT INTO dbo.items
VALUES(1, 1)
,(2, 3)
GO
CREATE VIEW dbo.vwLocationCodes
AS
WITH ru AS
SELECT
lh.lcID
,lh.lcCode
,lh.lcHID
,CAST('/' + lh.lcCode + '/' as varchar(8000)) as LocationPath
-- to support recursion
,lh.lcHIDParent
FROM dbo.LocationHierarchy lh
UNION ALL
SELECT
ru.lcID
,ru.lcCode
,ru.lcHID
,CAST('/' + lh.lcCode + ru.LocationPath as varchar(8000)) as LocationPath
,lh.lcHIDParent
FROM dbo.LocationHierarchy lh
JOIN ru ON ru.lcHIDParent = lh.lcHID
SELECT
lh.lcID
,lh.lcCode
,lh.LocationPath
,lh.lcHID
FROM ru lh
WHERE lh.lcHIDParent IS NULL
GO
-- get data via view
SELECT
CONCAT(SPACE(l.lcHID.GetLevel() * 4), lcCode) as LocationIndented
FROM dbo.vwLocationCodes l
ORDER BY lcHID
GO
--SET SHOWPLAN_XML ON
GO
DECLARE @lcID int = 2
-- I believe this produces bad plan and is defect in SQL Server optimizer.
-- variable value cardinality is 1 and SQL Server should know that. Optiomal plan is to do index seek with key lookup.
-- This does not happen.
SELECT lcCode FROM dbo.vwLocationCodes l WHERE l.lcID = @lcID-- OPTION(RECOMPILE) -- bad plan
-- this is a plan I expect.
SELECT lcCode FROM dbo.vwLocationCodes l WHERE l.lcID = 2 -- good plan
SELECT *
FROM dbo.Items itm
LEFT JOIN dbo.vwLocationCodes l ON l.lcID = itm.lcID
OPTION(RECOMPILE)
SELECT *
FROM dbo.Items itm
OUTER APPLY
SELECT *
FROM dbo.vwLocationCodes l
WHERE l.lcID = itm.lcID
) l
-- I reviewed these but I need a view here, can't be SP
-- http://sqlblogcasts.com/blogs/tonyrogerson/archive/2008/05/17/non-recursive-common-table-expressions-performance-sucks-1-cte-self-join-cte-sub-query-inline-expansion.aspx
-- http://social.msdn.microsoft.com/Forums/sqlserver/en-US/22d2d580-0ff8-4a9b-b0d0-e6a8345062df/issue-with-select-using-a-recursive-cte-and-parameterizing-the-query?forum=transactsql
GO
--SET SHOWPLAN_XML OFF
GO
ROLLBACK
Vladimir Moldovanenko
Similar Messages
-
hi, i am a littl confused as I logged into creative cloud and bough the in design plan for a year but i cant seem to donwload it... there is a window that pops up and it says its downloading but its taking forever? any advice?
Hi Dima,
Please refer to the help documents below:
Troubleshoot Creative Cloud download and install issues
Error downloading, installing, or updating Creative Cloud applications
Regards,
Sheena -
Hi
I am getting below error.
The query does not reference any table when attempting to build the WHERE clause. (IES 00022)
This error is in Validating Measue object in IDT.
It is not throwing error for dimensions objects but only for measure objects.
My BO version is 4.1
Backend is Teradata 14.1.
Regards
Gaurav.Hi
In the dimension/Measure definition, you can select the table. Find the below screenshot.
If you still getting the issue…Can you please share your screenshot, for better understanding the issue? -
My 4th generation ipod touch is not turning off when i hold the wake button for few seconds the Voice Control Function Starts Automatically.Please help me to get out of this problem.
Sorry i mistakenly made this question. It was alright. No Problem At ALL
-
Different query plans for same query on same DB
Hi,
HP-Ux
Oracle Database 10.2.0.4
We are experiencing a strange issue. One of our night batch process is taking invariably more time to execute. The process does not consume time at 1 particular query. Everyday we find a new query taking more time than previous execution.
Now, when we see the explain plan while the query is executing, we see NESTED LOOP SEMI (with improper index being used). At the same time if we take the query and see the explain plan seperately, we get HASH JOIN SEMI (with proper index being used). Also, if we execute this query with the values as in procedure, it finishes within mili seconds (as it should).
The tables and indexes are analyzed everyday before the process starts.
Can anybody explain, why the same query shows two different plans at the same time ?
Thanks a lot in advance :)Aalap Sharma wrote:
HP-Ux
Oracle Database 10.2.0.4
We are experiencing a strange issue. One of our night batch process is taking invariably more time to execute. The process does not consume time at 1 particular query. Everyday we find a new query taking more time than previous execution.
Now, when we see the explain plan while the query is executing, we see NESTED LOOP SEMI (with improper index being used). At the same time if we take the query and see the explain plan seperately, we get HASH JOIN SEMI (with proper index being used). Also, if we execute this query with the values as in procedure, it finishes within mili seconds (as it should).
The tables and indexes are analyzed everyday before the process starts.
Can anybody explain, why the same query shows two different plans at the same time ?As already mentioned, you might hit typical issues in 10.2: The column workload based SIZE AUTO statistics gathering feature and/or bind variable peeking.
How do you analyze the tables and indexes before the process starts? Can you share the exact call with parameters?
Some ideas:
1. If your process is "new", then the column workload monitoring of the database might recognize the column usage pattern and generate histograms on some of your columns. It might take a while until the workload has been established so that all columns got histograms according to the workload (It needs a certain number of usages/executions before the workload is registered as relevant). Until then you might get different execution plans each time the statistics are refreshed due to new histograms being added.
2. If the default 10g statistics gathering job is active, it might gather different statistics during the night than your individual job that runs prior to the processing. This could be one possible explanation why you get different plans on the next day.
3. "Bind Variable Peeking" is possibly another issue you might run into. How do you test the query so that you get a different, well performing plan? Does your original statement use bind variables? Do you use literals to reproduce? Note that using EXPLAIN PLAN on statements involving bind variables can lie, since it doesn't perform bind variable peeking by default.
Regards,
Randolf
Oracle related stuff blog:
http://oracle-randolf.blogspot.com/
SQLTools++ for Oracle (Open source Oracle GUI for Windows):
http://www.sqltools-plusplus.org:7676/
http://sourceforge.net/projects/sqlt-pp/ -
Bad explain plan for count(*)
select count(*) from foo
where flda = value and
fldba like 'text'
and contains(col,'some text') > 0
takes long time - does not use domain index.
If I replace count(*) w/*, runs like a champ, and uses domain index.
nullDefine a "good" or a "bad" execution plan.
See Wolfgang Breitling's Tuning by Cardinality Feedback:
http://www.centrexcc.com/Tuning%20by%20Cardinality%20Feedback.pdf
OBSERVATION
IF AN ACCESS PLAN IS NOT OPTIMAL IT IS BECAUSE THE CARDINALITY ESTIMATE FOR ONE OR MORE OF
THE ROW SOURCES IS GROSSLY INCORRECT."
CONJECTURE
THE CBO DOES AN EXCELLENT JOB OF FINDING THE BEST ACCESS PLAN FOR A GIVEN SQL PROVIDED
IT IS ABLE TO ACCURATELY ESTIMATE THE CARDINALITIES OF THE ROW SOURCES IN THE PLANSo the flipside of that is that if you can identify executions plans where the estimates were not accurate (see DBMS_XPLAN.DISPLAY_CURSOR) then it is more llikely that a suboptimal plan was used and more optimal plans are possible.
Edited by: Dom Brooks on Aug 21, 2012 1:06 PM
link /text missing for some reason -
Reading the DAX query plan of a trace against a query on a Tabular model
Hi,
I'm monitoring a Tabular model queried by an Excel workbook. Inside SQL Profiler I've choosen as events the VertiPaq SE Query End, the Query End and the DAX Query Plan. But this last event isn't more readable.
How can I read the info collected in the DAX Query Plan in a simple manner?
ThanksIt is fairly complex to read the DAX Query Plan. I don't think there are currently tools that make it easier to read. (Watch the DAX Studio project on codeplex as they may include tools for this in the future.) I would recommend you review the Tabular
Performance Guide which has a good explanation of the DAX Query Plan:
http://aka.ms/ASTabPerf2012
http://artisconsulting.com/Blogs/GregGalloway -
Download Links for JMS Explorer to view message and its details
Can i get the links for downloading the JMS explorer to view messages and its details on j2ee server.
I checked Hermesjms tool but found that it does not work with j2ee server.
Is there any other JMS explorer tool to view messages and its details on j2ee server specifically. -
[Solved] Referencing another View Objects Bind Variables
Hello,
I have a Master view object and a detail object.
The Master object, vProjects, has a bind variable :pProjectId that the user selects by using a selectOneChoice component. The View object vSections then shows only those Sections that have the selected ProjectId.
I have a view link to get to the lower level which connects vSections to vRequirements.
This works well except that the vRequirements lists all requirements that match the SecID I pass through the link. I need it to list only the ones that match the SecID AND the ProjectId chosen earlier.
Is there a way to reference the bind variable that I used in vProjects inside of vRequirements?
Thank you,
Nelson
Message was edited by:
TheNelsonThanks, I can't believe I didn't think of that. I was rewriting queries and everything.
Thanks again. -
TSQL for capture and insert to a user table when blcoking is happening on a SQL server
Hi,
I am searching for a TSQL which will capture the blocking script to a table with execution plan and all other necessaryu details. I tried with below script but its not giving the text for blocked statement
I t will be nice if i get RequestingText and BlockingTest
SELECT @@servername as Instancename,getdate() as [date],session_id,start_time,status,command,database_id,blocking_session_id,
wait_type,wait_time,last_wait_type,ST.TEXT AS SQL,
wait_resource,open_transaction_count,cpu_time,total_elapsed_time,reads,writes,logical_reads,text_size from sys.dm_exec_requests SR
CROSS APPLY SYS.DM_EXEC_SQL_TEXT(SR.SQL_HANDLE) AS ST
where blocking_session_id >0
I tried the below link also, this this script also got blocked
http://blog.sqlauthority.com/2010/10/06/sql-server-quickest-way-to-identify-blocking-query-and-resolution-dirty-solution/But when you run select * from sys.sysprocesses where blocked >0
i can see blocking
and it will be nice if I get RequestingText and BlockingTest
in the user table
You can get the requesting text for the spid that is blocked, plus all the other information you get from sys.sysprocesses by
select SUBSTRING(st1.text, (p.stmt_start/2)+1,
((CASE p.stmt_end
WHEN -1 THEN DATALENGTH(st1.text)
ELSE p.stmt_end
END - p.stmt_start)/2) + 1) AS RequestingText,
p.*
from sys.sysprocesses p
CROSS APPLY sys.dm_exec_sql_text(p.sql_handle) AS st1
where p.blocked <> 0;
But you will not bee able to get the command that caused the lock that is causing the blocking. SQL does not keep that information. For a lock, it only keeps the spid that owns it, what is locked, and the kind of lock. It does not keep
the command that caused the lock. And while you can, at least sometimes get the last command the blocking spid has issued, but that may well not be the command that caused the lock. The command that caused the lock might be anything the blocking
spid ran since it entered transaction state. And since that could be the last command or many, many commands ago, you won't be able to get that information with a query into the system tables and/or views.
Tom -
Data Services Designer Query tranform dynamic where clause or another way
I have an XML source that has 5 fields. These fields are used to query 4 different SQL table data sources and do an AND inthe where clause of a query transform. Works well if all 5 fields in the xml have data. If one (or more) are blank, then it runs the where checking for blank matches and gives no results. What I want to do is if a field is blank, do not use it in the where clause. Could this be an outer join setup? Issue is that if there is a PhoneNumber input, then to be considered a result, there must be a PhoneNumber match on potential result records...
I have an XML source that has 5 fields. These fields are used to query 4 different SQL table data sources and do an AND inthe where clause of a query transform. Works well if all 5 fields in the xml have data. If one (or more) are blank, then it runs the where checking for blank matches and gives no results. What I want to do is if a field is blank, do not use it in the where clause. Could this be an outer join setup? Issue is that if there is a PhoneNumber input, then to be considered a result, there must be a PhoneNumber match on potential result records...
-
Anyone have any tips how to get started with address labels? I went to my address book, but it looks so time intensive. Can I mail merge addresses I put into a excell spread sheet to print labels??
Don't waste your time with formatting in any of those programs - creating two pages for cards, blah blah blah.
The best way to mail merge on a mac is using address book.
People think merging got harder, but apple made it easier - more intuitive. You don't merge mailing labels through a word processor - you do it through the program which houses the addresses. If the addresses aren't in address book yet, that's a snap.
First, go to your program/file with the addresses (pages, numbers, excel, etc.). I think it's easiest to use numbers.
make sure the column headings are set to Mac Address Book Standard Names - that way you won't have to spend too much time mapping them in address book. (if you're not sure what those are - open address book and just a view a card/record, or open pages or numbers and search in the help menu for the term "merge field names" and it will give you a list. They're pretty simple - things like "First Name" "Last Name" "Street Address" etc.
For christmas cards, I add an extra column under the heading "Note" and input "Christmas Card List" for every record.
Once your data is formatted with the correct column names, export the list to a csv file.
Open Address book in mac and import the list - make sure the columns match up with the correct fields.
It might ask if you want to overwrite or update - that's up to you.
If you know your christmas card list has the most recent address info, hit update.
Once the import is done it should take you to the front page for the address book in which you'll be given the choice to view Icloud addresses (if you sync those) and also the Last import. Any groups or smart groups you have will show up in the list too.
Click on Last import - make sure all the addresses and names you just imported are there. If not, something went wrong - go back and check your import field mapping. If all's good, keep rollin'. (it helps to scroll to the bottom of the import list to get the count of imported records)
Here, you can do one of two things - create a group or a smart group.
For a regular group - Highlight all the records on the right panel in your last import, then go to file > new group from selection. Rename your group christmas cards or something like that.
I prefer to create smart groups.
For that, goto file > new smart group. You'll come to a filter window. Click on the first drop down box and scroll to "Note." Then in the second drop down box choose "is" and in the third and final input box on the right, enter the text from the note column you created in the address list file. I used "Christmas Card List".
That will create a smart group, such that any time you enter a new address or contact in the address book with the note field that equals "christmas Card list" it will automatically be entered into this group.
Either way, you're only one step away from labels.
With that Christmas Card List selected in address book, go to print. When the print dialogue box opens, make sure to click on the button for show details toward the bottom left. That will open up your choices for style.
Under "Style" click on mailing labels.
Under "Layout" choose your label layout (i use avery 5160). It will show you a picture of the label and you can tell if it's the right one. You'll also notice the labels are being merged correctly, with one address per label, rather than one name for the entire page - like if you try to do this through pages.
Print away.
Hope that helps.
Craig -
I just migrated to Apple and I'm having a little hard time adjusting.
When I send one of my peers and email I like to add a reminder for myself to do with follow-up in case the person does not reply. Is there a way to do this with mail application?You could drag the sent message to Reminders or Calendar to create a reminder.
-
Can't figure out how to install sql server for PHP
I am trying to install SQL Server for PHP on a server with Server 2008 32 bit. The exe from http://www.microsoft.com/en-us/download/details.aspx?id=20098 keeps tell me that it is an invalid win32 application. I've tried running as administrator
as well. Somewhere I read you need to open the exe with 7zip. I was able to do that and see all the files in there, but where do I go from there?
Thanks
Mike
edit: forgot to mention I'm using Apache for my serverThat solution is obsolete. The current solution is here:
http://msdn.microsoft.com/en-us/sqlserver/ff657782.aspx
bill ross -
How can I most easily get refunded for subscribing to Martha Stewart Living on iPad in error?
Normally there are no refunds, but you can try your luck.
You can report issues with your iTunes Store purchases directly through the iTunes Store:
http://support.apple.com/kb/HT1933
Maybe you are looking for
-
ABST2 Error while doing Fixed Assets Closing
Hi, I've run into an error of 0.01 in account 161370. I need to get past this or write off the difference in order to close the year.. Note: For 2008 Fixed assets closing i have executed ABST2 transaction now in this July-2009.When i execute ABST2,i
-
Using dbms_alert in Jdeveloper
Hello! I need check signal from OracleDatabase in my application on the JSP Page. How I can using dbms_alert package for my JSP page? Thanks.
-
Why is my iPad crashing when going into Wifi in the control panel?
Very bizarre incident I had today when I was at a local coffeeshop in my neighorhood. I was attempting to connect to their Wifi and everytime I tried to go into Wifi Settings on my iPad the iPad would crash. EVERYTIME. I tried rebooting, hard rese
-
Is mountain lion compatible with iBank?
I've been waiting to install mountain lion. Is there any compatibility issues with iBank 4.1.1? Is there any reason I should NOT upgrade to Mountain Lion? Thanks
-
Why does Firefox not block all popups? Example Netflicks
I was on HGTV site and when I closed Firefox, on my desktop was a Netflicks ad.