How much data to optimize our queries - sql-server

i have one table with this stracture and Indexs
CREATE TABLE [dbo].[Report4](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Mesc] [nvarchar](50) NULL,
[Line] [nvarchar](5) NULL,
[Unit] [nvarchar](5) NULL,
[Description] [nvarchar](500) NULL,
[ST_CODE] [nvarchar](5) NULL,
[PbsNo] [nvarchar](50) NULL,
[PbsDate] [nvarchar](10) NULL,
[PbsQty] [nvarchar](10) NULL,
[PbsQtyRec] [nvarchar](10) NULL,
[QtyConsum1] [nvarchar](10) NULL,
[QtyConsum2] [nvarchar](10) NULL,
[QtyConsum3] [nvarchar](10) NULL,
[QtyConsum4] [nvarchar](10) NULL,
[QtyConsum5] [nvarchar](10) NULL,
[Type] [nvarchar](20) NULL,
[InvQty] [nvarchar](10) NULL,
[TypeRequest] [nvarchar](50) NULL,
[HeaderId] [bigint] NULL,
[LOCATION] [nvarchar](10) NULL,
CONSTRAINT [PK_Report4] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [HeaderId] ON [dbo].[Report4]
(
[HeaderId] ASC
)
INCLUDE ( [Id],
[Mesc],
[Line],
[Unit],
[Description],
[ST_CODE],
[PbsNo],
[PbsDate],
[PbsQty],
[PbsQtyRec],
[QtyConsum1],
[QtyConsum2],
[QtyConsum3],
[QtyConsum4],
[QtyConsum5],
[Type],
[InvQty],
[TypeRequest]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [HeaderIdRAll] ON [dbo].[Report4]
(
[HeaderId] ASC
)
INCLUDE ( [Id],
[Mesc],
[Line],
[Unit],
[Description],
[ST_CODE],
[PbsNo],
[PbsDate],
[PbsQty],
[PbsQtyRec],
[QtyConsum1],
[QtyConsum2],
[QtyConsum3],
[QtyConsum4],
[QtyConsum5],
[Type],
[InvQty],
[TypeRequest]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [LineNOIRHeaderId] ON [dbo].[Report4]
(
[Line] ASC
)
INCLUDE ( [HeaderId])
WHERE ([line]='I')
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [LineNoRHeaderId] ON [dbo].[Report4]
(
[Line] ASC
)
INCLUDE ( [HeaderId])
WHERE ([line]='H')
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [LineNoRMesc] ON [dbo].[Report4]
(
[Line] ASC
)
INCLUDE ( [Mesc])
WHERE ([line]='I')
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [MescRAll] ON [dbo].[Report4]
(
[Mesc] ASC
)
INCLUDE ( [Id],
[Line],
[Unit],
[Description],
[ST_CODE],
[PbsNo],
[PbsDate],
[PbsQty],
[PbsQtyRec],
[QtyConsum1],
[QtyConsum2],
[QtyConsum3],
[QtyConsum4],
[QtyConsum5],
[Type],
[InvQty],
[TypeRequest],
[HeaderId]) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
i want run this Query for this table
ALTER PROCEDURE [dbo].[SPSelectReport2] (#StringWhereParameter nvarchar(4000),#PageIndex int,#PageSize int )
AS
BEGIN
SET NOCOUNT ON;
-- َ Begin Of Transaction
begin tran
declare #from int=(#PageSize*(#PageIndex-1))+1
declare #to int=(#PageIndex*#PageSize)
declare #Query nvarchar(max)
set #Query=' select
distinct id, [Mesc], [Line]
,[Unit]
,[Discription]
,[InvQty]
,[LastDateNil]
,[StCode]
,[PlanCode]
,[MIN]
,[MAX]
,[LastDateConsum]
,[PbsNo]
,[PbsDate]
,[PbsQty]
,[PbsQtyRec]
,[DateDelay]
,[TypeRequest]
,[HeaderId]
,LOCATION
from (
SELECT *, ROW_NUMBER() OVER(ORDER BY Id) ROW_NUM
FROM(
((SELECT Id,[Mesc]
,[Line]
,[Unit]
,[Discription]
,[InvQty]
,[LastDateNil]
,[StCode]
,[PlanCode]
,[MIN]
,[MAX]
,[LastDateConsum]
,[PbsNo]
,[PbsDate]
,[PbsQty]
,[PbsQtyRec]
,[DateDelay]
,[TypeRequest]
,[HeaderId]
,LOCATION
FROM [MyMaterialDB].[dbo].[Report2]
WHERE headerid IN(SELECT HeaderId FROM [MyMaterialDB].[dbo].[Report2] WHERE line=''H'''+ #StringWhereParameter+'))
UNION
(
(SELECT Id,[Mesc]
,[Line]
,[Unit]
,[Discription]
,[InvQty]
,[LastDateNil]
,[StCode]
,[PlanCode]
,[MIN]
,[MAX]
,[LastDateConsum]
,[PbsNo]
,[PbsDate]
,[PbsQty]
,[PbsQtyRec]
,[DateDelay]
,[TypeRequest]
,[HeaderId]
,LOCATION
FROM [MyMaterialDB].[dbo].[Report2]
WHERE mesc IN(SELECT mesc FROM [MyMaterialDB].[dbo].[Report2] WHERE line=''I''' +#StringWhereParameter+'))
UNION
(SELECT Id, [Mesc]
,[Line]
,[Unit]
,[Discription]
,[InvQty]
,[LastDateNil]
,[StCode]
,[PlanCode]
,[MIN]
,[MAX]
,[LastDateConsum]
,[PbsNo]
,[PbsDate]
,[PbsQty]
,[PbsQtyRec]
,[DateDelay]
,[TypeRequest]
,[HeaderId]
,LOCATION
FROM [MyMaterialDB].[dbo].[Report2]
WHERE mesc IN(SELECT HeaderId FROM [MyMaterialDB].[dbo].[Report2] WHERE line=''I'''+#StringWhereParameter+')
)))) a)b where b.ROW_NUM between '+CAST(#from as varchar(10))+' and '+CAST(#to as varchar(10))
-- Order by Mesc,Line,unit
exec(#Query)
--print #Query
--
if ##error = 0
Commit Tran
Else
rollback tran
End
into this table i have more then 1000000 records and when run this sp ,It takes ten minutes or more. How do I optimize the structure or query. please help me. thanks all.

For starters you MUST do the following (I think only those actions can take your query execution time down to much less than a minute):
remove every in clause. select ... from ... where a in (select ...) is a) very very very slow, b)dangerous as it can run your sql server out of memory -especially for large datasets like yours-. You must change all in clauses to left outer joins, it is very easy to do this.
remove distinct clause. This forces your query to do order by (behind the schenes) and generally is very slow too. Try to rephrase your query so that records are already distinct
As long as you have distinct data you must also change union to union all. Union is same as distinct union which goes as my previous statement. If you use union all you will see great improvement to your query... as long as you can bring your data to not needed to be distinct...
If you manage to make at least 2 of the 3 previous changes, i think you will see great improvement. If you can handle all of them, you will have a very fast query.
And also, do not bother changing your sql exec into a 'precompliled' stored procedure. I don't think you will gain an significant improvement by doing this (I see you have dynamic where so this wouldn't be applicant in any case).
Please, tell me if that worked.

Related

Delete all indexes of a table and rebuild them

I need to delete all indexes (other than clustered index) of a table and rebuild them all.
For example, I have the following structure:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[SP6](
[SP6_REGCLI] [char](10) NOT NULL,
[SP6_REGEMP] [char](4) NOT NULL,
[SP6_FILIAL] [char](2) NOT NULL,
[SP6_CODDEP] [char](9) NOT NULL,
[SP6_DESCRI] [char](40) NULL,
[SP6_FOLGA] [char](1) NULL,
[SP6_HESOAU] [char](1) NULL,
[SR_RECNO] [numeric](15, 0) IDENTITY(1,1) NOT NULL,
CONSTRAINT [PK__SP6] PRIMARY KEY NONCLUSTERED
(
[SR_RECNO] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE CLUSTERED INDEX [SP6_SR] ON [dbo].[SP6]
(
[SR_RECNO] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
CREATE NONCLUSTERED INDEX [SP601_1_REG] ON [dbo].[SP6]
(
[SP6_REGCLI] ASC,
[SP6_REGEMP] ASC,
[SP6_FILIAL] ASC,
[SP6_CODDEP] ASC,
[SR_RECNO] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
SET ANSI_PADDING ON
GO
CREATE NONCLUSTERED INDEX [SP602_2_REG] ON [dbo].[SP6]
(
[SP6_REGCLI] ASC,
[SP6_REGEMP] ASC,
[SP6_FILIAL] ASC,
[SP6_DESCRI] ASC,
[SR_RECNO] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
In this structure I have to delete all the NONCLUSTERED indexes (i.e. the index SP6_SR won't be deleted).
I need to do this because I have to change the size of some columns that is part of some indexes. For example, if I try to change the size of the colum SP6_DESCRI to Char(50) an error occurs because the column is part of index SP602_2_REG.
I think that if I delete all indexes of a table, change the size of columns desired and then rebuild all indexes, everything will be fine.
Can anyone help me please?
Thank you so much!

Delete 2 rows using IN () on a child table creates has match of 197 millions rows

Why would deleting 2 rows using IN() on a child table create a hash match of 197 million rows, this query times out in the app, but deleting 1 row using = or IN() works fine and completes instantly?
Exec plans and queries:
DELETE FROM dbo.ClientDepartmentContact WHERE ClientDepartmentContactId IN (12126,12127)
https://www.brentozar.com/pastetheplan/?id=rkKueM6HS
DELETE FROM dbo.ClientDepartmentContact WHERE ClientDepartmentContactId = 12126
https://www.brentozar.com/pastetheplan/?id=Sku2lGaBr
The primary/foreign keys relationship are not set to to cascade.
DDLs:
CREATE TABLE [dbo].[ClientDepartmentContact](
[ClientDepartmentContactId] [int] IDENTITY(1,1) NOT NULL,
[ClientId] [int] NOT NULL,
[DepartmentId] [smallint] NOT NULL,
[DispatchContactId] [int] NOT NULL,
[DispatchType] [char](1) NOT NULL,
[DispatchContactType] [char](1) NOT NULL,
CONSTRAINT [PK_ClientDepartmentContact] PRIMARY KEY CLUSTERED
(
[ClientDepartmentContactId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [UK_ClientDepartmentContact] UNIQUE NONCLUSTERED
(
[ClientId] ASC,
[DepartmentId] ASC,
[DispatchContactId] ASC,
[DispatchType] ASC,
[DispatchContactType] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
--Index
ALTER TABLE [dbo].[ClientDepartmentContact] ADD CONSTRAINT [PK_ClientDepartmentContact] PRIMARY KEY CLUSTERED
(
[ClientDepartmentContactId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
ALTER TABLE [dbo].[ClientDepartmentContact] ADD CONSTRAINT [UK_ClientDepartmentContact] UNIQUE NONCLUSTERED
(
[ClientId] ASC,
[DepartmentId] ASC,
[DispatchContactId] ASC,
[DispatchType] ASC,
[DispatchContactType] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE TABLE [dbo].[ClientDepartmentContact](
[ClientDepartmentContactId] [int] IDENTITY(1,1) NOT NULL,
[ClientId] [int] NOT NULL,
[DepartmentId] [smallint] NOT NULL,
[DispatchContactId] [int] NOT NULL,
[DispatchType] [char](1) NOT NULL,
[DispatchContactType] [char](1) NOT NULL,
CONSTRAINT [PK_ClientDepartmentContact] PRIMARY KEY CLUSTERED
(
[ClientDepartmentContactId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
CONSTRAINT [UK_ClientDepartmentContact] UNIQUE NONCLUSTERED
(
[ClientId] ASC,
[DepartmentId] ASC,
[DispatchContactId] ASC,
[DispatchType] ASC,
[DispatchContactType] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
--Index
ALTER TABLE [dbo].[ClientDepartmentContact] ADD CONSTRAINT [PK_ClientDepartmentContact] PRIMARY KEY CLUSTERED
(
[ClientDepartmentContactId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
ALTER TABLE [dbo].[ClientDepartmentContact] ADD CONSTRAINT [UK_ClientDepartmentContact] UNIQUE NONCLUSTERED
(
[ClientId] ASC,
[DepartmentId] ASC,
[DispatchContactId] ASC,
[DispatchType] ASC,
[DispatchContactType] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE TABLE [dbo].[DispatchContact](
[DispatchContactId] [int] IDENTITY(1,1) NOT NULL,
[Email] [varchar](254) NOT NULL,
CONSTRAINT [PK_DispatchContact] PRIMARY KEY CLUSTERED
(
[DispatchContactId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE UNIQUE NONCLUSTERED INDEX [IX_ContactAddress_Email] ON [dbo].[DispatchContact]
(
[Email] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
ALTER TABLE [dbo].[DispatchContact] ADD CONSTRAINT [PK_DispatchContact] PRIMARY KEY CLUSTERED
(
[DispatchContactId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
SQL version 2012 standard, all stats are up to date.
Before asking for help, i have restored to the DB to a 2014 and 2017 (both standard) dev instance and cant recreate the exec plan, the queries exec instantly on those. The plan for the 2017 is:
https://www.brentozar.com/pastetheplan/?id=BJdpX76rH
Stats are updated via a maintenance job nightly, but I did update all stats while investigating the issue. I have tried adding index's using SentryOnes Plan explorer Index analysis tool to no avail.
ps Thanks for your help

How can I optimize this query which works with 24M row table?

I have a table with 24 milion rows.
I want to run this query:
select r1.userID, r2.userID, sum(r1.rate * r2.rate) as sum
from dbo.Ratings as r1
join dbo.Ratings as r2
on r1.movieID = r2.movieID
where r1.userID <= r2.userID
group by r1.userID, r2.userID
As I tested, it took 24 hours to produce 0.02 percent of the final result.
How can I speed it up?
Here is the definition of the table:
CREATE TABLE [dbo].[Ratings](
[userID] [int] NOT NULL,
[movieID] [int] NOT NULL,
[rate] [real] NOT NULL,
PRIMARY KEY CLUSTERED
(
[userID] ASC,
[movieID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_RatingsMovies] ON [dbo].[Ratings]
(
[movieID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [IX_RatingsUsers] ON [dbo].[Ratings]
(
[userID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
Here is the execution plan:
The workaround I suggested was to create a "reverse" index:
CREATE INDEX IX_Ratings_Reverse on Ratings(movieid, userid) include(rate);
and then force SQL Server to use it:
select r1.userID, r2.userID, sum(r1.rate * r2.rate) as sum
from dbo.Ratings as r1 join dbo.Ratings as r2
with (index(IX_Ratings_Reverse))
on r1.movieID = r2.movieID
where r1.userID <= r2.userID group by r1.userID, r2.userID
There are two things that might help.
1) Change the order of columns in your clustered index to MovieID,UserID. This would group all the same MovieID's together first, which might change your Hash Match to an Inner Loop, and improve the performance of the JOIN.
2) Change the [IX_RatingsMovies] index to INCLUDE UserID and Rate. The more I think about it, I think this is less likely than my first suggestion to help. But it's possible.

Create a stored procedure to populate a table from other (multiple) table columns

I need to create a stored procedure transaction that will pull data from two tables and create a random integer to populate a third table (dbo.patient_address).
I want the following, but I am having a hard time understanding how to script this as a stored procedure.
dbo.address AddressID = dbo.patient_address AddressID,
dbo.patient PatientID = dbo.patient_address PatientID,
RAND is an integer between 1-3 (see dbo.addresstype) = dbo.patient_address AddressTypeID
Below are create statements of all of these tables.
ADDRESS TABLE - 30000 rows in place (complete data set)
CREATE TABLE [dbo].[ADDRESS](
[AddressID] [int] NOT NULL,
[StreetAddress] [varchar](50) NULL,
[City] [varchar](50) NULL,
[State] [varchar](50) NULL,
[PostalCode] [varchar](50) NULL,
CONSTRAINT [ADDRESS_PK] PRIMARY KEY CLUSTERED
(
[AddressID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
PATIENT TABLE - 30000 rows in place (complete data set)
CREATE TABLE [dbo].[PATIENT](
[PatientID] [int] NOT NULL,
[PatientFName] [varchar](50) NOT NULL,
[PatientLName] [varchar](50) NOT NULL,
[GenderID] [int] NOT NULL,
[DateOfBirth] [date] NOT NULL,
CONSTRAINT [PATIENT_PK] PRIMARY KEY CLUSTERED
(
[PatientID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ADDRESS TYPE - 3 choices (home, billing, work) – integer between 1 - 3
CREATE TABLE [dbo].[ADDRESS_TYPE](
[AddressTypeID] [int] NOT NULL,
[AddressTypeName] [varchar](10) NOT NULL,
[AddressTypeDescr] [varchar](10) NULL,
CONSTRAINT [ADDRESS_TYPE_PK] PRIMARY KEY CLUSTERED
(
[AddressTypeID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
INSERT INTO [dbo].[ADDRESS_TYPE]
([AddressTypeID],[AddressTypeName],[AddressTypeDescr])
Values ('1','Home','Home'), ('2','Bill','Billing'), ('3','Work','Work')
This is the final table that I want to populate from all of the above tables using a stored procedure transaction.
CREATE TABLE [dbo].[PATIENT_ADDRESS](
[PatientID] [int] NOT NULL,
[AddressID] [int] NOT NULL,
[AddressTypeID] [int] NULL,
CONSTRAINT [PATIENT_ADDRESS_PK] PRIMARY KEY CLUSTERED
(
[PatientID] ASC,
[AddressID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Try this:
INSERT INTO PATIENT_ADDRESS
SELECT PatientID, AddressID,
CONVERT(INT,(ABS(CHECKSUM(NEWID())/2148000000.))*3)+1 AS AddressTypeID
FROM (
SELECT PatientID, ROW_NUMBER() OVER (ORDER BY PatientID) AS RowNum
FROM dbo.PATIENT
) x
INNER JOIN (
SELECT AddressID, ROW_NUMBER() OVER (ORDER BY AddressID) AS RowNum
FROM dbo.ADDRESS
) y ON x.RowNum = y.RowNum

sp_executesql not using index?

I'm using nHibnerate in my web application and I have a problem using indexes in generated sp_execute. My table has 210 millions records and the query is very slow.
Firstly, there was a problem with generated column 'kolumna1' type. In database I have a column of varchar but nHibernate generated nvarchar. I workarounded this by putting special attribute in the code which forced using varchar. After that trick sp_executed started using indexes and everything was correct. Now the problem is back sp_executesql takes 10 minutes to finish. When i checked normal query(without sp_executesql) it took only 1s. I checked execution plans for both: sp_executesql wasn't using index and normal query was using index. Without changing index i modified back varchar to nvarchar and sp_execute finished in 1s (used index). Anyone got any idea where did i make a mistake ? why the execution plan is diffrent for such small changes? And how to fix it?
Here i attached more code. Just in case if someone need it.
sp_executesql with varchar(8000)
exec sp_executesql N'SELECT count(*) as y0_ FROM tabela1 this_ WHERE ((this_.kolumna2 >= #p0 and this_.kolumna2 <= #p1)) and
(this_.kolumna3 in (#p2, #p3) and this_.kolumna1 like #p4)',N'#p0 datetime,#p1 datetime,#p2 int,#p3 int,#p4 varchar(8000)',
#p0='2013-01-08 14:38:00' ,#p1='2013-02-08 14:38:00',#p2=341,#p3=342,#p4='%501096109%'
sp_executesql with nvarchar(4000)
exec sp_executesql N'SELECT count(*) as y0_ FROM tabela1 this_ WHERE ((this_.kolumna2 >= #p0 and this_.kolumna2 <= #p1)) and
(this_.kolumna3 in (#p2, #p3) and this_.kolumna1 like #p4)',N'#p0 datetime,#p1 datetime,#p2 int,#p3 int,#p4 nvarchar(4000)',
#p0='2013-01-08 14:38:00' ,#p1='2013-02-08 14:38:00',#p2=341,#p3=342,#p4='%501096109%'
The funny part is that in sql profiler both query gives same reuslt:
exec sp_executesql N'SELECT count(*) as y0_ FROM tabela1 this_
WHERE this_.kolumna3 in (#p2, #p3) and ((this_.kolumna2 >= #p0 and this_.kolumna2 <= #p1))
and ( this_.kolumna1 like #p4)',N'#p0 datetime,#p1 datetime,#p2 int,#p3 int,#p4 varchar(8000)',
#p0='2013-01-08 14:38:00' ,#p1='2013-02-08 14:38:00',#p2=341,#p3=342,#p4='%501096109%'
--Declare #p0 datetime
--set #p0 = '2013-01-08 14:38:00'
--Declare #p1 datetime
--set #p1 = '2013-02-08 14:38:00'
--Declare #p2 int
--set #p2 = 341
--Declare #p3 int
--set #p3 = 342
--Declare #p4 varchar(8000)
--set #p4 = '%501096109%'
--SELECT count(*) as y0_
--FROM tabela1 this_
--WHERE ((this_.kolumna2 >= #p0 and
--this_.kolumna2 <= #p1)) and
--(this_.kolumna3 in (#p2, #p3) and this_.kolumna1 like #p4)
Here are indexes:
CREATE TABLE [dbo].[tabela1](
[id] [bigint] NOT NULL,
[kolumna1] [varchar](128) NOT NULL,
[kolumna2] [datetime] NOT NULL,
[kolumna3] [int] NOT NULL,
CONSTRAINT [PK__tabela1__4F7CD00D] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
CREATE NONCLUSTERED INDEX [ind_tabela1_ kolumna2] ON [dbo].[tabela1]
(
[kolumna2] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [ind_ tabela1_ kolumna3] ON [dbo].[ tabela1]
(
[kolumna3] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_ tabela1_ kolumna1] ON [dbo].[ tabela1]
(
[kolumna1] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_ tabela1_ kolumna2_ kolumna3] ON [dbo].[ tabela1]
(
[kolumna2] ASC,
[kolumna3] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
CREATE NONCLUSTERED INDEX [IX_ tabela1_ kolumna3_ kolumna2_id_ kolumna1] ON [dbo].[ tabela1]
(
[kolumna3] ASC,
[kolumna2] ASC,
[id] ASC,
[kolumna1] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Below execution plan for query: select count(*) from [dbo].[tabela1] where [kolumna1] like N'%501096109%'
Sql Server query optimizer can choose to use index seek when:
There are another filter predicates besides LIKE. It should be a precise search or at least SARGable predicate
Table is very large (millions of rows)
But seek operation cannot be done when explicit type conversion is used - different collation/datatype.
Another thing that you cannot control this behavior and query plans can be vary for different predicate sets. To do this, you need to use hint FORCESEEK (version 2008+). You can find information here:
http://msdn.microsoft.com/en-us/library/ms187373%28v=sql.100%29.aspx
Could you try this:
(1) Run the following SQL:
select * from sys.dm_exec_cached_plans
cross apply sys.dm_exec_sql_text(plan_handle) t
(2) Use the last column to find the SQL for the first query. It will not contain sp_executesql, but will start with your list of parameters, the last one being a varchar. Get the plan_handle, and use it in the following statement:
dbcc freeproccache (<your_plan_handle>)
Then retry query 1.

Resources