Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2008 Forums
 Transact-SQL (2008)
 Trigger or View If Need To Index View

Author  Topic 

phenreid
Starting Member

29 Posts

Posted - 2010-11-22 : 12:42:46
I have a situation where I need a field in my master table to keep track of the number of recs in my child table that have Status='A' (active). A pretty common requirement.

I can do it with a view several ways. One involves creating a view of the PK + active counts and left joining to it because I need it to show zero of there are no active child recs.

The other uses a DT/Subselect to return that field. Both operate fast and accurately.

But, the problem is that with either left join or DT in a view, I can no longer give it a unique index and that is a requirement for my application that requires one unique index in order for the table to be updateable by my front-end app.

Therefore, I am going to add an ActiveCount field to my parent table and use a trigger to update it. I hate to use a trigger to "post" a count that can be obtained with a view -- but I do need to be able to index the view for multiple reasons.

As far as I know, if you want to add a DT or left join to a view, it is no longer indexable and there is no way around that. Several of my queries suggest the use of indicies on this view -- not just the front-end app.

So, where you want to index a view and also include a DT or left join in the select, this is a good example where trigger is justified, true?

(I realize that this view vs. trigger trade-off depends on how much activity the trigger will get -- in this case it is quite reasonable.)

Thx.

X002548
Not Just a Number

15586 Posts

Posted - 2010-11-22 : 12:50:04
Who told you that rubbish

A derived column is out of date the minute you update it..unless you add the overhead of a trigger




CREATE myView99 VIEW
AS
SELECT master.Col_Keys, COUNT(*)
FROM master.Col_Keys = Child.Col_Keys
GROUP BY master.Col_Keys




Brett

8-)

Hint: Want your questions answered fast? Follow the direction in this link
http://weblogs.sqlteam.com/brettk/archive/2005/05/25/5276.aspx


Want to help yourself?

http://msdn.microsoft.com/en-us/library/ms130214.aspx

http://weblogs.sqlteam.com/brettk/

http://brettkaiser.blogspot.com/


Go to Top of Page

russell
Pyro-ma-ni-yak

5072 Posts

Posted - 2010-11-22 : 13:48:14
Actually phenreid is correct. I think you missed the "Indexed View" part Brett.
Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2010-11-22 : 18:20:33
Can you have a Filtered Index on a VIEW to keep the NULL rows out of the index?
Go to Top of Page

russell
Pyro-ma-ni-yak

5072 Posts

Posted - 2010-11-22 : 19:29:12
Filtered indexes are only supported on tables, so no, can't do it.
Go to Top of Page

X002548
Not Just a Number

15586 Posts

Posted - 2010-11-22 : 20:27:35
WAIT

Are you saying that the view with the key and the count

SELECT *
FROM Table JOIN VIEW
ON Key=key
WHERE Key = x

is going to cause a scan?

OR

SELECT *
FROM Table
JOIN (SELECT * FROM VIEW WHere key =x )
ON key = key
WHERE Key = x

is also going to scan

I'm lost, and I don't want to logon

But I will check it out tomorrow




Brett

8-)

Hint: Want your questions answered fast? Follow the direction in this link
http://weblogs.sqlteam.com/brettk/archive/2005/05/25/5276.aspx


Want to help yourself?

http://msdn.microsoft.com/en-us/library/ms130214.aspx

http://weblogs.sqlteam.com/brettk/

http://brettkaiser.blogspot.com/


Go to Top of Page

X002548
Not Just a Number

15586 Posts

Posted - 2010-11-22 : 20:28:24
and if that's the case...you can take Billy outback and SHORT him

Brett

8-)

Hint: Want your questions answered fast? Follow the direction in this link
http://weblogs.sqlteam.com/brettk/archive/2005/05/25/5276.aspx


Want to help yourself?

http://msdn.microsoft.com/en-us/library/ms130214.aspx

http://weblogs.sqlteam.com/brettk/

http://brettkaiser.blogspot.com/


Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2010-11-23 : 01:09:31
quote:
Originally posted by russell

Filtered indexes are only supported on tables, so no, can't do it.



I feared that would be the case. Next version maybe
Go to Top of Page

TimSman
Posting Yak Master

127 Posts

Posted - 2010-11-23 : 08:43:15
OK, random thought here, and I may not be understanding the requirements completely, so bear with me.

My understanding is that you need to keep a running total of records that have a specified status (currently, that status is 'A', but in my experience, that could change or be added).

Why don't you create a separate table that gets updated, either by sproc(s) or trigger(s)? One entry for each status code, and a current total. You could also store the last amount, date updated, etc. in there as well.
Go to Top of Page

phenreid
Starting Member

29 Posts

Posted - 2010-11-23 : 14:30:49
Without describing the whole application -- I have to join three master-record (non-transactional) tables into a view that is updateable by my UI. I need to see the number of records in one of the tables that has Status='A' in another table, in my view somehow.

I realize it could be out-of-date when presented, but that is a non-issue for my situation. Small number of users; not a lot of simultaneous processing -- if it were changed while the view was on someone's screen that is no big deal.

I hate to keep a "posted" count somewhere with a trigger when I can just get the count. BUT, for UI to see the view as an UPDATEABLE recordset it has to be WITH SCHEMABINDING, and has to have one unique key. Also, in various execution plans other indicies were suggested on this view that really help a lot.

However, to get the count (which could be zero) I need some sort of subselect or a left join. Either of these make the view unable to index. I even tried creating a view with the coutns that has all the records so I could do an inner join to my main view, but even that prevented indexing.

Purpose of this post was to confirm this restriction is real and there is no workaround; therefore, I added a field to the appropriate table (I called it ActiveCount) and I keep it current by trigger. I did that, but wanted to make sure I did not use a trigger unnecessarily. Seems odd to me that I'm keeping a count in a table field that is readily available with an on-the-fly COUNT(*).

By the way, in my trigger, I only want to update ActiveCount if the status field was actually updated, or if the entire record was inserted or deleted. I couldn't immediately find a way to do this because IF UPDATE(status) only works for updates. IF Exists (select * from inserted) tells me if there was a new record. But what about deletes? How do I tell that it's a delete with no update, if there's no corresponding record in INSERTED by joining INSERTED To DELETED? Is there a function to determine if the trigger action is just deleted? Is it: "IF Exists(select * from Deleted) And UPDATE(status)=false": so the trigger IF would be:
  If UPDATE(status) or EXISTS (Select * from Inserted) or (EXISTS (select * from Deleted) And UPDATE(status)=false)
UPDATE TableA SET ActiveCount = Select count(*)....


I don't want to run an update statement for other fields being updated.

Go to Top of Page

X002548
Not Just a Number

15586 Posts

Posted - 2010-11-23 : 15:08:34
Why do you have to update the view?



Brett

8-)

Hint: Want your questions answered fast? Follow the direction in this link
http://weblogs.sqlteam.com/brettk/archive/2005/05/25/5276.aspx


Want to help yourself?

http://msdn.microsoft.com/en-us/library/ms130214.aspx

http://weblogs.sqlteam.com/brettk/

http://brettkaiser.blogspot.com/


Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2010-11-24 : 04:46:53
"I hate to keep a "posted" count somewhere with a trigger when I can just get the count"

My take on that is it depends on the number of Reads to Writes, In Forum Software continuously dynamically calculating the number of Posts a user has made would be prohibitive - there are millions (some exaggeration!!) of Reads for each Write that would require incrementing the post count.

However, if you have a running-total table/column you have to be sure it is correctly maintained. What happens if the moderator deletes a post? Calculating it doesn't have that issue of course.

Maybe your scenario has more Writes than Reads - in which case Calculation might be better.

Calculation, IMHO, also falls down when the number of rows to Count is large. It will take time EVERY time, and scale badly.

"Seems odd to me that I'm keeping a count in a table field that is readily available with an on-the-fly COUNT(*)."

If you had a billion rows to count would you still think that? (I wouldn't !!). At that point you would be creating the trigger for Performance Reasons. I don't find it objectionable to do it in order to have a NOT NULL column in the view (and the Performance Benefit might well be a bonus - even if that is down-stream). Either way ... I can talk myself into it!

"However, to get the count (which could be zero) I need some sort of subselect or a left join"

Two VIEWs? Your query INNER JOINs to the first and OUTER JOINs to the second, both can be indexed. Might plkay merry hell with trying to have an update-able view though.

"IF UPDATE(status) only works for updates"

And not all that usefully even then. "UPDATE(status)" is TRUE if the [status] column was included in the UPDATE statement, regardless of whether its value actually changed. It obviosuly has merit to weed out updates that were NOT on the status column (with very low processing cost), but you still need a "Did the value really change" type test.

If this is an UPDATE trigger there will be an identical number of rows in INSERTED and DELETED tables.

If the trigger is ALSO for INSERT and/or DELETE then there will be an unequal number of rows when either of those two scenarios arrises,

Typical route to maintaining a counter where you have to worry about all three of Insert, Update and Delete would be:

UPDATE C
SET TheCount = TheCount + COALESCE(I.SomeQty) - COALESCE(D.SomeQty)
FROM INSERTED AS I
FULL OUTER JOIN DELETED AS D
ON D.MyID = I.MyID
JOIN MyCountTable AS C
ON C.SomeID = COALESCE(I.SomeID, D.SomeID)

You are dealing with count of records, I think, rather than SUM of a moving total - such as Stock level - so you probably just need

SET TheCount = TheCount + CASE WHEN I.MyID IS NULL THEN 0 ELSE 1 END - CASE WHEN D.MyID IS NULL THEN 0 ELSE 1 END

then you want a WHERE clause to stop this updating any rows where there will be a NETT effect of nothing. Perhaps this?

WHERE (I.MyID IS NULL OR D.MyID IS NULL)

which will only update TheCount if there is an INSERT of DELETION but not an UPDATE. In your case its probably a bit more complicated in terms of NOT updating on an UPDATE where STATUS=a and it has NOT changed in the update, but updating for INSERT AND Status=A, DELETE AND Status=A or an update where either the INSERTED or DELETED data is Status=A, but not both.
Go to Top of Page
   

- Advertisement -