For WPF, the ObservableCollection<(Of <(T>) makes it easy to create classes that are aware of changes, inserts, and deletions. This class automatically works with the UI to notify it of these changes.
You can use this class in the User Interface collection. The easiest way to use it is to create an instance of the ObservableCollection and pass your business layer class to the constructor.
Read more about this class at: http://msdn.microsoft.com/en-us/library/ms668604.aspx
Ken
Have you ever gone to learn from a presentation, communicate at an ask the experts session or explored an environment through a hands on lab and felt that a little input from you could have turned the information provided into more contextual knowledge for you?
Have you ever felt too intimidated to ask the important question in front of a large crowd?
Well this year Solid Quality Mentors are offering you the chance to schedule a consultancy session with their mentors about anything that you intend to learn, communicate about or explore during the conference. Being Solid Quality Mentors this means that you can ask about just about anything SQL Server that you would like to find out more about.
Just pop over to our stand and book an available session that suits you, for a relaxed chat with one of our mentors present at TechEd.
Come and communicate with us, we can help you explore what you need and learn from what we know.
Look out for our mentors in the Exhibition Hall, B14 the first week and B21 the second week.
Look out for our mentors at ask the expert sessions.
Look out for our mentor' presentation sessions including :-
Maciej Pilecki: Where Is My Memory? Understanding Microsoft SQL Server Memory Usage and Management
SQL Server, like any other database, can be very memory-intensive but how is all that memory used. Is it just the data that is cached? What other objects can be chached to make the system more efficient? This session goes deep under the covers of SQL OS to see how SQL Server manages its memory. We will look at the dynamics of memory usage within SQL Server and the competition between different cache types. Special attention will be afforded to the procedure cache and how it is utilised. We will also examine how SQL OS interacts with the host operating system and other applications running on the same machine. After this session you will have a good understanding about the SQL Server memory architecture and how to optimise SQL Server by configuring memory usage optimally. You will also learn how to diagnose and troubleshoot memory related issues.
Greg Low: Answering the Queries your users really want to
ask, with Full-Text Search in SQL Server 2008
Business users today are less prepared to be constrained by technology than they may have been in the past. They don't want to hear that you cannot search on such and such because it is not in the right field or that it has not been isolated from other elements so it cannot be retrieved fast enough or will have a negative impact on other users. The full-text search capabilities in SQL Server 2008 will give you the power to deal with these loosely constrained queries.
This session will familiarise you with the full-text search subsystem. It will show you why it is important, what can be done with it and how to implement and manage it.
The subsystem is not new but it has been optimised for delivery within the latest version of SQL Server. The benefits will be communicated during the session as will issues that you may experience if you are upgrading a previous version of the subsystem.
Whether you are new to FullText search or you have tried it previously and were frustrated by the limitations of the earlier version, you will gain a full appreciation of why you should be considering it as a new flexible way of meeting your business users needs.
Greg Low: Using Dynamic Management Views To Improve Your Development
Although Dynamic Management Views have been available as objects in previous releases of SQL Server, they have been extended and made much more Functional in SQL Server 2008. However, it appears that the majority of developers have tended to ignore the fact that they are available.
In this session you will be introduced to these management object types, both views and functions, and aquainted with those that are considered most useful to the developer. You will learn how they can be valuable when monitoring and troubleshooting as well as general management of SQL Server, hands up if you have worked on a project without a DBA!.
As well as showing you how you as a developer can benefit from these objects, you will also learn how you can help your team, those that perhaps don't manage to make it to TechEd. To this end you will learn how these objects can be used to develop customised reports which can be run from inside SQL Server Management Studio.
Greg Low: Avoiding Stored Procedure Recompiles in SQL Server 2008
In this session, Greg will describe the process by which SQL Server executes stored procedures and how it decides whether or not recompilations are necessary. He will discuss how to monitor recompilations and explain in detail the specific triggers that cause recompilation. Greg will then discuss techniques to be used when writing database code to help avoid the need for recompilations and to help keep systems performing well.
By the way, we will be giving away copies of Itzik Ben-Gan’s latest book, http://www.sql.co.il/books/tsqlfund2008/, to some of the lucky visitors to our booth within the exhibition hall..
Do we or don’t we have a recession? Our politicians are debating largely about this topic since a year ago. In fact, it is interesting to know that the official technical determination of the term “recession” is different in Europe and the USA.
Are we living challenging times? No question about it. However, we see this time as an opportunity time as well. Excellent companies are going to survive this crisis (or recession, if you prefer this term), and they are becoming stronger and stronger. At the same time, weaker companies disappear, leaving market opportunities to the stronger ones, which in turn will make them even stronger.
This is the time to wisely invest in knowledge, analyzing processes, optimizing resources, and preparing each company to be ready by the time the market will get back on track again.
I already passed through this process before. International economy is a recurring wave that makes us going up and down every few years. And I’ve always seen the same type of companies survive and get stronger and the other type of companies disappear.
Is it the time of investing in training? Absolutely! Many of our customers understand that. Training gives them a technical edge that places them beyond the competition. Training encourages their employees to move forward technically, being more productive to their companies, and improving their own professional value (earning a personal market advantage as well).
Is it time to cut staff cost? Is it time to reduce the total cost of the tasks that our technical staff needs to perform? Well, I could not say that this would be the time to increase these costs, while companies are fighting for survival. However, cutting the total cost per task, and the total cost per project, does not mean cutting the hourly rate you pay for these services. Cutting the total cost per project means finishing the project with the minimum cost, using wisely all available resources, achieving or exceeding the expected and contractual quality level.
We see many times that employing the best available professionals, who typically charge the highest rates, results in shorter delivery times, higher quality, and higher benefits overall. Even more, adding just a handful of key professionals (in many cases just one is enough) to a project, can represent the difference between success or failure, between profitability or disaster.
Because spending wisely just an extra 3%, might represent in many cases the chance to cut down the total cost in more than 20%. And that 20% might be the difference between success or failure of a project, which might mean the difference between life or death of a company, a division or department, in these challenging times.
Remembering the legendary Supertramp title… Crisis, What Crisis?
I am very proud I can finally officially announce the Bleeding Edge conference. This is a conference I am preparing together with Matevž Gačnik and Dušan Zupančič. It is a conference prepared by developers for developers. This one-day highly technical event is going to take place on October 1st, 2008, in Portorož, Slovenia. Save the date, or even hurry up with registration!
Here's a quick update on happenings! I have some great things coming down the pipe for me and also its been a busy 12 months! But yes, blogging hasn't been my forte, but it's not for a lack of interest. I hope to catch up a little in the next few months.
Looking to the future
What I have been doing the last few months?
I’ve got some more things in the pipeline that I can’t share yet, but stay tuned!
Erik
...on practical BI
I have been playing around with the latest SQL Server 2008 CTP while trying to keep both my performance tuning and DBA classes updated with the latest changes. When I review new releases of SQL Server, I tend to evaluate the release by determining which features and functionalities that will help me solve problems that I could not solve or could not solve easily in earlier releases.
One of the problems that did not have easy solutions in earlier versions was the one faced when dealing with large amounts of data. Many times I have incorporated many different strategies to lessen the impact of large amounts of data on queries by trying to lessen the amount of data contained within the indexes on a table. This often involved partitioning the tables in SQL Server 2005 or archiving data in earlier versions. Any method that worked to create a smaller set of active data to be queried during each SELECT statement and a smaller index to be maintained during data modifications.
One of the great new performance improvements in SQL Server 2008 is the new filtered index. Filtered indexes basically allow you to create a filter on an index – think WHERE clause. The index B-Tree will only contain the rows of data that meet the filtering criteria. This allows you to reduce the amount of data contained in an index which means that you are also reducing the data affected in an index by data modifications.
I am going to walk through a very small and simple demo that illustrates the impact of filtered indexes.
First let’s create a demo table with some demo data
SET NOCOUNT ON
--Create demo table
IF OBJECT_ID('TestTable','table') IS NOT NULL
DROP TABLE TestTable
GO
CREATE TABLE TestTable
(colID INT IDENTITY(1,1)
,colDate DATETIME
,colSession INT
,colDesc VARCHAR(100)
)
--Insert data into table
DECLARE @loop INT
SET @loop = 1000
WHILE @loop > 0
BEGIN
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070301',1,'20070301-1' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070401',1,'20070401-1' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070501',1,'20070501-1' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070601',1,'20070601-1' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070701',1,'20070701-1' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070801',1,'20070801-1' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070901',1,'20070901-1' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20071001',1,'20071001-1' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20071101',1,'20071101-1' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20071201',1,'20071201-1' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20080101',1,'20080101-1' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20080201',1,'20080201-1' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20080301',1,'20080301-1' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070301',2,'20070301-2' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070401',2,'20070401-2' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070501',2,'20070501-2' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070601',2,'20070601-2' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070701',2,'20070701-2' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070801',2,'20070801-2' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070901',2,'20070901-2' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20071001',2,'20071001-2' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20071101',2,'20071101-2' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20071201',2,'20071201-2' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20080101',2,'20080101-2' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20080201',2,'20080201-2' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20080301',2,'20080301-2' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070301',3,'20070301-3' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070401',3,'20070401-3' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070501',3,'20070501-3' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070601',3,'20070601-3' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070701',3,'20070701-3' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070801',3,'20070801-3' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20070901',3,'20070901-3' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20071001',3,'20071001-3' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20071101',3,'20071101-3' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20071201',3,'20071201-3' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20080101',3,'20080101-3' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20080201',3,'20080201-3' )
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20080301',3,'20080301-3' )
SET @loop = @loop - 1
END
Next we will create a clustered Index and a non-filtered nonclustered index
--Create clustered index on table
CREATE CLUSTERED INDEX cl_TestTable_1 ON TestTable(colID)
--Create nonclustered index on table
CREATE NONCLUSTERED INDEX ncl_TestTable_1 ON TestTable(colDate) INCLUDE (colSession)
After creating the indexes, let’s take a look at the number of rows in the indexes
--View number of rows in indexes
SELECT name, i.index_id, [rows]
FROM sys.partitions p
INNER JOIN sys.indexes i
ON p.[object_id] = i.[object_id]
AND p.index_id = i.index_id
WHERE p.[object_id] = OBJECT_ID('TestTable')
You should get an output similar to the one below
/*
name index_id rows
cl_TestTable_1 1 39000
ncl_TestTable_1 2 39000
*/
Now let’s create a filtered index and look at the number of rows of data
--Create filtered index
CREATE NONCLUSTERED INDEX ncl_TestTable_2 ON TestTable(colDate) INCLUDE (colSession)
WHERE colDate > '12/31/2007 23:59:59'
ncl_TestTable_2 3 9000
Once we are done with creating the infrastructure, let’s look at how they affect performance.
--How does a filter index help SELECTS
--Clear cache for demo
CHECKPOINT
DBCC DROPCLEANBUFFERS
--Get execution plan and IO statistics
SET STATISTICS PROFILE ON
SET STATISTICS IO ON
--Select by date
--This has a bookmark lookup
SELECT * FROM TestTable WITH (INDEX = 2) WHERE colDate > '12/31/2007 23:59:59'
--Table 'TestTable'. Scan count 1, logical reads 19692
--TotalSubtreeCost: 2.11023
--Use filtered index
SELECT * FROM TestTable WITH (INDEX = 3) WHERE colDate > '12/31/2007 23:59:59'
--Table 'TestTable'. Scan count 1, logical reads 18598
-- TotalSubtreeCost: 2.096156
--This does not have a bookmark lookup
SELECT colID, colDate, colSession FROM TestTable WITH (INDEX = 2) WHERE colDate > '12/31/2007 23:59:59'
--Table 'TestTable'. Scan count 1, logical reads 27
-- TotalSubtreeCost: 0.03095978
SELECT colID, colDate, colSession FROM TestTable WITH (INDEX = 3) WHERE colDate > '12/31/2007 23:59:59'
-- TotalSubtreeCost: 0.0168857
--Turn off execution plans
SET STATISTICS PROFILE OFF
SET STATISTICS IO OFF
--Insert new rows of data
--Will affect filtered index
INSERT INTO TestTable (colDate,colSession,colDesc ) VALUES ('20080301',3,'20080301-3')
cl_TestTable_1 1 39001
ncl_TestTable_1 2 39001
ncl_TestTable_2 3 9001
--Determine which pages have been changed
SELECT DB_NAME(bd.database_id) AS 'Database Name'
,dtab.object_name AS 'Object Name'
,dtab.index_id AS 'Index number with dirty page'
,bd.page_id AS 'Page ID of dirty page'
,bd.page_type AS 'Type of Page'
,bd.page_level AS 'Page Level'
FROM sys.dm_os_buffer_descriptors AS bd
INNER JOIN
(
SELECT OBJECT_NAME([object_id]) AS object_name
,index_id ,allocation_unit_id
FROM sys.allocation_units AS au
INNER JOIN sys.partitions AS p
ON au.container_id = p.hobt_id
AND (au.type = 1 OR au.type = 3)
UNION ALL
,index_id, allocation_unit_id
ON au.container_id = p.partition_id
AND au.type = 2
) AS dtab
ON bd.allocation_unit_id = dtab.allocation_unit_id
WHERE bd.is_modified = 1
AND bd.database_id = DB_ID()
AND [object_name] = 'TestTable'
ORDER BY bd.database_id, [Object Name],index_id, page_type
Database Name
Object Name
Index number with dirty page
Page ID of dirty page
Type of Page
Page Level
AdventureWorks2005
TestTable
1
19578
DATA_PAGE
0
2
20033
INDEX_PAGE