all groups > sql server programming > november 2004 >
You're in the

sql server programming

group:

Performance Issue


Performance Issue Ramnadh
11/15/2004 9:33:02 PM
sql server programming:
Message
----------
Id int 4 (Primary Key)
SenderId int 4
SentOn datetime 8
Subject Title 500
PriorityTypeId 4
TypeId int 4
Message text 16
SentState varchar 2
SentFlag bit 1
FolderId int 4

MessageRecipient
--------------------
MessageId int 4 (Foreign Key refers Message (Id))
RecipientId int 4
MessageState varchar 2
ExtRecipient Email 100
BelongsTo bit 1
IsNew bit 1

Indexes on MessageRecipient table :
MessageId : Non-Clustered Index
RecipientId : Clustered Index

Message Table is having 218,493 rows and
MessageRecipient Table is having 171,915 rows

The rows in the Message and MessageRecipient Table will increase by 100 to
200 every day.

When i am executing the below query it will give 2000 rows as output in
which it is taking 19 sec. of time. When i see the execution Plan 75% of time
was taken for Clustered Index Scan On the Message (Id) table where it is
scanning all 218,493 rows which is taking lot of time to scan through.Can
anyone please try to help me out.

Any help is highly appreciated. Thanx for help in advance.

SELECT MSGS.Id
, MSGS.SentOn
, MSGS.Subject
, MSGR.MessageState
, MSGS.Message
, MSGS.FolderId
, dbo.GetMessageRecipientsFn(MSGS.Id, 0) AS 'To'
, dbo.GetMessageRecipientsFn(MSGS.Id, 1) AS 'Cc'
, MSGR.IsNew
FROM dbo.Message MSGS (NOLOCK)
INNER JOIN dbo.MessageRecipient MSGR (NOLOCK)
ON MSGS.Id = MSGR.MessageId
AND ISNULL(MSGR.MessageState,'') NOT IN ('TD','PD')
AND MSGR.RecipientId = 32
ORDER BY MSGS.SentOn DESC

Re: Performance Issue Ramnadh
11/15/2004 10:22:01 PM
Yes, even if i removed the functions it is taking so much time and it is
doing clustered index scan on Message (Id).

I also checked by making the MessageId,RecipientId as the clustered Index on
the MessageRecipient Table.

It is still doing the Clustered Index Scan on Message (Id) on all the rows
in the table.

This is the query plan that i got while executing this query.

|--Compute Scalar(DEFINE:([MSGS].[Message]=[MSGS].[Message]))
|--Compute
Scalar(DEFINE:([Expr1002]=[dbo].[GetMessageRecipientsFn]([MSGS].[Id], 0),
[Expr1003]=[dbo].[GetMessageRecipientsFn]([MSGS].[Id], 1)))
|--Sort(ORDER BY:([MSGS].[SentOn] DESC))
|--Merge Join(Inner Join,
MERGE:([MSGS].[Id])=([MSGR].[MessageId]),
RESIDUAL:([MSGR].[MessageId]=[MSGS].[Id]))
|--Clustered Index
Scan(OBJECT:([Viper_Onsite].[dbo].[Message].[PK_Message] AS [MSGS]), ORDERED
FORWARD)
|--Clustered Index
Scan(OBJECT:([Viper_Onsite].[dbo].[MessageRecipient].[IX_MessageRecipient_MsgRecipient]
AS [MSGR]), WHERE:(([MSGR].[RecipientId]=[@recipientId] AND
[MSGR].[MessageState]<>'PD') AND [MSGR].[MessageState]<>'TD')

These are the statistics i got while executing Stored Procedure.

Table 'MessageRecipient'. Scan count 1, logical reads 545, physical reads 0,
read-ahead reads 0.
Table 'Message'. Scan count 1, logical reads 3368, physical reads 0,
read-ahead reads 3335.

Thanx for reply.

[quoted text, click to view]
Re: Performance Issue Ramnadh
11/15/2004 11:36:02 PM
I had already kept the index in SentState and check it. But no luck it is
also taking more time and doing clustered index scan on Message (Id) table
for all the rows.

I am providing the script for creating two tables inserting the 100 rows for
each table.

drop table MessageRecipient
go
drop table Message
go

CREATE TABLE [dbo].[Message] (
[Id] [int] IDENTITY (1, 1) NOT NULL ,
[SenderId] [int] NULL ,
[SentOn] [datetime] NOT NULL ,
[Subject] [varchar] (500) NOT NULL ,
[PriorityTypeId] [int] NULL ,
[TypeId] [int] NOT NULL ,
[Message] [text] COLLATE SQL_Latin1_General_Pref_CP437_CI_AS NULL ,
[SentState] [varchar] (2) COLLATE SQL_Latin1_General_Pref_CP437_CI_AS NULL ,
[SentFlag] [bit] NULL ,
[FolderId] [int] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

ALTER TABLE [dbo].[Message] WITH NOCHECK ADD
CONSTRAINT [PK_Message] PRIMARY KEY CLUSTERED
(
[Id]
) WITH FILLFACTOR = 95 ON [PRIMARY]
GO

CREATE INDEX [IX_Message_SentState] ON [dbo].[Message]([SentState]) ON
[PRIMARY]
GO


CREATE TABLE [dbo].[MessageRecipient] (
[MessageId] [int] NOT NULL ,
[RecipientId] [int] NULL ,
[MessageState] [varchar] (2) COLLATE SQL_Latin1_General_Pref_CP437_CI_AS
NOT NULL ,
[ExtRecipient] [varchar] (100) NULL ,
[BelongsTo] [bit] NULL ,
[IsNew] [bit] NOT NULL
) ON [PRIMARY]
GO

CREATE CLUSTERED INDEX [IX_MessageRecipient_RecipientId] ON
[dbo].[MessageRecipient]([RecipientId]) ON [PRIMARY]
GO

ALTER TABLE [dbo].[MessageRecipient] ADD
CONSTRAINT [DF_MessageState] DEFAULT ('U') FOR [MessageState],
CONSTRAINT [DF_MessageRecipient_IsNew] DEFAULT (1) FOR [IsNew]
GO

CREATE INDEX [IX_MessageRecipient_MessageId] ON
[dbo].[MessageRecipient]([MessageId]) ON [PRIMARY]
GO

ALTER TABLE [dbo].[MessageRecipient] ADD
CONSTRAINT [FK_MessageRecipient_MessageId] FOREIGN KEY
(
[MessageId]
) REFERENCES [dbo].[Message] (
[Id]
)
GO



DECLARE @i INT
SET @i = 0

WHILE (@i<100)
BEGIN
INSERT INTO Message
(SenderId,SentOn,Subject,PriorityTypeId,TypeId,Message,SentState,SentFlag)
VALUES
( 1,GetDate(),'Test',66,158,'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0
Transitional//EN"> <HTML><HEAD> <META http-equiv=Content-Type
content="text/html; charset=unicode"> <META content="MSHTML 6.00.2800.1106"
name=GENERATOR></HEAD> <BODY></BODY></HTML>'
,'R',1)
SET @i = @i + 1
END

SET @i = 0

WHILE (@i<100)
BEGIN
INSERT INTO MessageRecipient
(MessageId,RecipientId,MessageState,ExtRecipient,BelongsTo,IsNew) VALUES
( @i,32,'DU',NULL,1,0)
SET @i = @i + 1

END

Thanx for the help.

[quoted text, click to view]
Re: Performance Issue Ramnadh
11/16/2004 1:05:02 AM
ok, I had removed the Order By , ISNULL and User defined function and run the
Query. This is the query plan it is giving

|--Compute Scalar(DEFINE:([MSGS].[Message]=[MSGS].[Message]))
|--Merge Join(Inner Join,
MERGE:([MSGS].[Id])=([MSGR].[MessageId]),
RESIDUAL:([MSGR].[MessageId]=[MSGS].[Id]))
|--Clustered Index
Scan(OBJECT:([Viper_Onsite].[dbo].[Message].[PK_Message] AS [MSGS]), ORDERED
FORWARD)
|--Sort(ORDER BY:([MSGR].[MessageId] ASC))
|--Clustered Index
Seek(OBJECT:([Viper_Onsite].[dbo].[MessageRecipient].[CI_MessageRecipient_RecipientId]
AS [MSGR]), SEEK:([MSGR].[RecipientId]=[@recipientId]) ORDERED FORWARD)



[quoted text, click to view]
Re: Performance Issue Ramnadh
11/16/2004 3:34:01 AM
HI rao,
any luck with the query why is doing clustered index scan on all the rows of
the table.
I doesn't get it till now.

thanx for you help.

[quoted text, click to view]
RE: Performance Issue Scott Simons
11/16/2004 5:53:02 AM
try this

SELECT MSGS.Id
, MSGS.SentOn
, MSGS.Subject
, MSGR.MessageState
, MSGS.Message
, MSGS.FolderId
, dbo.GetMessageRecipientsFn(MSGS.Id, 0) AS 'To'
, dbo.GetMessageRecipientsFn(MSGS.Id, 1) AS 'Cc'
, MSGR.IsNew
FROM dbo.Message MSGS (NOLOCK)
INNER JOIN dbo.MessageRecipient MSGR (NOLOCK)
ON MSGS.Id = MSGR.MessageId
WHERE
(MSGR.MessageState = 'TD' or MSGR.MessageState = 'PD')
AND MSGR.RecipientId = 32
ORDER BY MSGS.SentOn DESC

Re: Performance Issue Ramnadh
11/16/2004 5:53:04 AM
It is still showing Clustered Index Scan on the Message (Id) table.
I again tried by creating new table and inserting rows.

But still it is doing clustered index scan on all the rows of the table and
it is taking about 81% of the time.

Can u please execute the below script again and try once. I am unable to get
why was it showing 13% for clustered index scan in ur query.

Please check it once. Thanx for your help.

drop table MessageRecipient
go
drop table Message
go

CREATE TABLE [dbo].[Message] (
[Id] [int] IDENTITY (1, 1) NOT NULL ,
[SenderId] [int] NULL ,
[SentOn] [datetime] NOT NULL ,
[Subject] [varchar] (500) NOT NULL ,
[PriorityTypeId] [int] NULL ,
[TypeId] [int] NOT NULL ,
[Message] [text] COLLATE SQL_Latin1_General_Pref_CP437_CI_AS NULL ,
[SentState] [varchar] (2) COLLATE SQL_Latin1_General_Pref_CP437_CI_AS NULL ,
[SentFlag] [bit] NULL ,
[FolderId] [int] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

ALTER TABLE [dbo].[Message] WITH NOCHECK ADD
CONSTRAINT [PK_Message] PRIMARY KEY CLUSTERED
(
[Id]
) WITH FILLFACTOR = 95 ON [PRIMARY]
GO

CREATE INDEX [IX_Message_SentState] ON [dbo].[Message]([SentState]) ON
[PRIMARY]
GO


CREATE TABLE [dbo].[MessageRecipient] (
[MessageId] [int] NOT NULL ,
[RecipientId] [int] NULL ,
[MessageState] [varchar] (2) COLLATE SQL_Latin1_General_Pref_CP437_CI_AS
NOT NULL ,
[ExtRecipient] [varchar] (100) NULL ,
[BelongsTo] [bit] NULL ,
[IsNew] [bit] NOT NULL
) ON [PRIMARY]
GO

CREATE CLUSTERED INDEX [IX_MessageRecipient_RecipientId] ON
[dbo].[MessageRecipient]([RecipientId]) ON [PRIMARY]
GO

ALTER TABLE [dbo].[MessageRecipient] ADD
CONSTRAINT [DF_MessageState] DEFAULT ('U') FOR [MessageState],
CONSTRAINT [DF_MessageRecipient_IsNew] DEFAULT (1) FOR [IsNew]
GO

CREATE INDEX [IX_MessageRecipient_MessageId] ON
[dbo].[MessageRecipient]([MessageId]) ON [PRIMARY]
GO

ALTER TABLE [dbo].[MessageRecipient] ADD
CONSTRAINT [FK_MessageRecipient_MessageId] FOREIGN KEY
(
[MessageId]
) REFERENCES [dbo].[Message] (
[Id]
)
GO



DECLARE @i INT
SET @i = 0

WHILE (@i<200000)
BEGIN
INSERT INTO Message
(SenderId,SentOn,Subject,PriorityTypeId,TypeId,Message,SentState,SentFlag)
VALUES
( 1,GetDate(),'Test',66,158,'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0
Transitional//EN"> <HTML><HEAD> <META http-equiv=Content-Type
content="text/html; charset=unicode"> <META content="MSHTML 6.00.2800.1106"
name=GENERATOR></HEAD> <BODY></BODY></HTML>'
,'R',1)
SET @i = @i + 1
END

SET @i = 1

WHILE (@i<100000)
BEGIN
INSERT INTO MessageRecipient
(MessageId,RecipientId,MessageState,ExtRecipient,BelongsTo,IsNew) VALUES
( @i,32,'DU',NULL,1,0)
SET @i = @i + 1

END
[quoted text, click to view]
RE: Performance Issue Ramnadh
11/16/2004 6:07:01 AM
scott this statement looks wrong for me.

(MSGR.MessageState = 'TD' or MSGR.MessageState = 'PD')

as we are checking for the rows satisfy this condition

ISNULL(MSGR.MessageState,'') NOT IN ('TD','PD')

which is not equivalent to above condition.

any help is appreciated.
[quoted text, click to view]
Re: Performance Issue avnrao
11/16/2004 11:22:54 AM
looking at the indexes you created, it should ideally do clustered index
seek on Message table.
what do you have in the GetMessageRecipientFn? what does it do? comment it
out and see if does Clustered index scan?
can you include Recipient ID and Message ID in Clustered index on
MessageRecipient table?

this query explains better what you are thinking to do..but the order of the
statements will not have any effect on optimization..

SELECT MSGS.Id
, MSGS.SentOn
, MSGS.Subject
, MSGR.MessageState
, MSGS.Message
, MSGS.FolderId
, dbo.GetMessageRecipientsFn(MSGS.Id, 0) AS 'To'
, dbo.GetMessageRecipientsFn(MSGS.Id, 1) AS 'Cc'
, MSGR.IsNew
FROM dbo.MessageRecipient MSGR (NOLOCK)
INNER JOIN dbo.Message MSGS (NOLOCK)
ON MSGS.Id = MSGR.MessageId
AND MSGR.RecipientId = 32
AND ISNULL(MSGR.MessageState,'') NOT IN ('TD','PD')
ORDER BY MSGS.SentOn DESC

try this and let us know..

Av.
http://dotnetjunkies.com/WebLog/avnrao
http://www28.brinkster.com/avdotnet


[quoted text, click to view]

Re: Performance Issue avnrao
11/16/2004 12:25:39 PM
looks like it is doing clustered index scan on MessageRecipient table also.
that shud not be the case here.
is it because MessageState? do you have index on MessageState?

it would be good if you generate scripts for creating tables, indexes and
some data about 100 rows or so in both these tables.
i can try and let you know..

Av.
http://dotnetjunkies.com/WebLog/avnrao
http://www28.brinkster.com/avdotnet

[quoted text, click to view]
Scan(OBJECT:([Viper_Onsite].[dbo].[MessageRecipient].[IX_MessageRecipient_Ms
gRecipient]
[quoted text, click to view]

Re: Performance Issue avnrao
11/16/2004 1:53:48 PM
unfortunately its doing clustered index seek on these 100 rows.
let me create 218,493 and 171,915 rows and run the query.

before that..can you post query plan for these scenarios
1. comment Order by clause and run
2. comment IsNull clause and run
3. comment GetMessageRecipientsFn and run.

this would pin point which statement is causing the scan..

Av.
http://dotnetjunkies.com/WebLog/avnrao
http://www28.brinkster.com/avdotnet



[quoted text, click to view]
Re: Performance Issue avnrao
11/16/2004 5:23:00 PM
hey Ramnadh,
I could create 2 tables with 218,493 and 171,915 rows.
when i ran the query, i saw this execution plan :



as you said, clustered index scan on Message table was taking lot of =
time (75%)..but it takes only 13% of it.
i guess the clustered index scan on Message table is unavoidable..and =
scan on MessageRecipient table is because of NOT IN ('TD','PD') clause.
how did it show 75% for you?

Av.
http://dotnetjunkies.com/WebLog/avnrao
http://www28.brinkster.com/avdotnet




[quoted text, click to view]
Seek(OBJECT:([Viper_Onsite].[dbo].[MessageRecipient].[CI_MessageRecipient=
_RecipientId]=20
[quoted text, click to view]
(SenderId,SentOn,Subject,PriorityTypeId,TypeId,Message,SentState,SentFlag=
)
[quoted text, click to view]
on all the
RE: Performance Issue Scott Simons
11/17/2004 10:03:02 AM
sorry, I meant

RE: Performance Issue Ramnadh
11/17/2004 8:34:01 PM
sorry Scott, the performance problem it is still doing the clustered index
scan on the Message (Id) Column.

what i am trying to change is if the MessageState Column can be made from
varchar to INT.

Can it give any change in the choosing the Other options rather than
Clustered Index Scan.

[quoted text, click to view]
AddThis Social Bookmark Button