Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Entity–attribute–value model wikipedia , lookup
Extensible Storage Engine wikipedia , lookup
Microsoft Access wikipedia , lookup
Microsoft Jet Database Engine wikipedia , lookup
Relational model wikipedia , lookup
Clusterpoint wikipedia , lookup
Database model wikipedia , lookup
Open Database Connectivity wikipedia , lookup
Architecting Effective SQL Server Data Access Solutions Adam Machanic Database Consultant Data Manipulation Group, Inc. About Adam Machanic Independent Software Consultant SQL Server and .NET Specialist SQL Server MVP Co-author, Pro SQL Server 2005 (Apress) SQL Server 2005 “Expert”, www.SearchSQLServer.com [email protected] © 2006 Adam Machanic Data Access == A Big Headache Implementation differences Type differences Objects and relations are not compatible paradigms SQL Server types and .NET types are not aligned Build and deployment mismatch The processes used to “compile” application and database are totally different © 2006 Adam Machanic Segmentation of Logic First problem: Too much intermingling of logic Where does your logic really belong? First, define what we’re dealing with: Data Logic Business Logic Application/UI Logic © 2006 Adam Machanic Data Logic Rules for data consistency and correctness Keys, constraints, etc. Data-tier validation Data rules are often codified business rules! The database must be able to enforce any and all rules necessary to ensure that the data is correct Example rule: Accounts without overdraft protection cannot go into the red © 2006 Adam Machanic Business Logic Business logic dictates what to do with the data, and when to do it How to transform the data in order to meet business requirements How to manipulate the data to make business decisions (i.e., how to turn data into knowledge) © 2006 Adam Machanic Application Logic User interface behaviors String/numeric/date formatting rules Localization Anything that has more to do with displaying data than actually manipulating it © 2006 Adam Machanic The Hierarchy DATA LOGIC, SOME BUSINESS LOGIC BUSINESS LOGIC APP LOGIC BUSINESS LOGIC BUSINESS LOGIC APP LOGIC APP LOGIC © 2006 Adam Machanic ANY LOGIC? Architectural concepts: A quick review Coupling Cohesion How dependent is a module on another module it uses? Do your routines do exactly one thing? Encapsulation How much do your routines know about the modules they use? © 2006 Adam Machanic Coupling class Dealership { //name of the dealership string Name; //owner of the dealership string Owner; //cars that the dealership has Car[] Cars; //defining the Car subclass class Car { //make of the car string Make; //model of the car string Model; } } class CarOwner { //name of the car owner string name; //the owner’s cars Dealership.Car[] Cars } TOO MUCH DEPENDENCY == TIGHT COUPLING © 2006 Adam Machanic Cohesion bool TransferFunds( Account AccountFrom, Account AccountTo, decimal Amount) { if (AccountFrom.Balance >= Amount) AccountFrom.Balance -= Amount; else return(false); AccountTo.Balance += Amount; return(true); } WHY DOES “TRANSFER” KNOW HOW TO DEPOSIT AND WITHDRAW? © 2006 Adam Machanic Cohesion bool TransferFunds( Account AccountFrom, Account AccountTo, decimal Amount) { bool success = false; success = Withdraw(AccountFrom, Amount); if (!success) return(false); success = Deposit(AccountTo, Amount); if (!success) return(false); else return(true); } © 2006 Adam Machanic Encapsulation bool Withdraw( Account AccountFrom, decimal Amount) { if (AccountFrom.Balance >= Amount) { AccountFrom.Balance -= Amount; return(true); } else return(false); } SHOULD “WITHDRAW” HANDLE THESE ESSENTIAL RULES FOR THE ACCOUNT CLASS? © 2006 Adam Machanic Encapsulation bool Withdraw( Account AccountFrom, decimal Amount) { return (Account.Withdraw(Amount)); } LET THE CLASS HANDLE ITS OWN RULES! © 2006 Adam Machanic What does this have to do with data access? Data access routines are just like any other routines Application developers sometimes forget the rules when it comes to data access Why can’t the database itself be treated just like an object? © 2006 Adam Machanic The Key: Data Interfaces (stored procedures!) Properly designed stored procedures provide… Encapsulation of data and schema … which leads to loose coupling between the application and the database… … which leads to much more cohesive application-level code… If the database is thought of as an object, stored procedures are nothing but methods! © 2006 Adam Machanic Interfaces Stable, encapsulated access to underlying resources Consistent inputs, consistent outputs Defines a “contract” Stored procedures define “implicit” contracts – not enforceable, but still testable © 2006 Adam Machanic The Database as API Mindset Application sees the database as a black box Stored procedures become cohesive “action” interfaces Get(XXXX) Update(XXXX) Delete(XXXX) Have a database problem? No need to fix the application. © 2006 Adam Machanic The Interface Balance Testability Maintainability Security Performance Creeping Featurism © 2006 Adam Machanic Testability Avoid polymorphic interfaces “Flexible” is a bad thing when it comes to testing Partition functionality – avoid combinatorial explosions (think about cohesion) © 2006 Adam Machanic Maintainability Maintainability is concerned with both interfaces and actual code “Flexible” may mean less maintainable Flexible interfaces may tightly couple the caller to the routine Flexible code may be more complex Tie-in with testability: The easier a routine is to test, the easier it will be to maintain! © 2006 Adam Machanic A problematic stored procedure CREATE PROCEDURE myGreatProc @ColumnList NVARCHAR(500) AS BEGIN SET NOCOUNT ON DECLARE @sql NVARCHAR(2000) SET @sql = 'SELECT ' + @ColumnList + 'FROM myTable ‘ EXEC (@sql) END How many possible combinations of columns can be passed in? What if they’re passed in a different order? What if the column names in the database change? Does not returning all of the columns every time really make that much of a difference? © 2006 Adam Machanic Security Complex security schemes can make testing and maintenance more difficult (and expensive) How many test combinations are required to test all authentication schemes? Can you be sure that both sides of the security question are covered—what you can access as well as what you can’t? © 2006 Adam Machanic Most important (and easily fixed) security question: Injection! Always, always, always parameterize queries! .NET: Use Parameters collection SQL Server: Use sp_executesql if you’re using dynamic SQL © 2006 Adam Machanic Performance Performance can sometimes have greater value than correctness More security can often mean lower performance Simpler, more testable/maintainable modules often tend to exhibit better performance! Encapsulating access within a stored procedure often makes it easier to fix performance issues © 2006 Adam Machanic Performance impact: Chatty interfaces Try to merge multiple calls into a single call Remember: Scaling the application or Web server is often cheaper than scaling the SQL Server! © 2006 Adam Machanic Creeping Featurism Do you have properties, methods, or objects marked, “Reserved for Future Use”? Does adding unused complexity upfront help later – or simply add to increased maintenance cost in the interim? Adding features tomorrow should be a secondary concern to producing working software today. © 2006 Adam Machanic Other interface hints Use column aliases to help keep interfaces consistent even when schemas change SELECT ProductNo FROM Products SELECT ProductNumber AS ProductNo FROM Products © 2006 Adam Machanic Other interface hints Optional parameters? Dynamic SQL is your friend! CREATE PROCEDURE GetMyData1 @Param1 INT AS CREATE PROCEDURE GetMyData2 @Param2 INT … AS CREATE PROCEDURE GetMyData3 … @Param1 INT, @Param2 INT AS … © 2006 Adam Machanic Dynamic SQL – PARAMETERIZED DECLARE @sql NVARCHAR(100) SET @sql = 'SELECT ColA, ColB, ColC ' + 'FROM YourTable ' + 'WHERE 1=1 ' + CASE WHEN @Param1 IS NOT NULL THEN 'AND YourCol1 = @Param1 ‘ ELSE '' END + CASE WHEN @Param2 IS NOT NULL THEN 'AND YourCol2 = @Param2 ‘ ELSE '' END EXEC sp_executesql @sql, N'@Param1 INT, @Param2 INT', @Param1, @Param2 © 2006 Adam Machanic Other interface hints Avoid use of SELECT * in stored procedures Do you really need a dynamic table name? The CASE expression is your friend; use it when you need to change output order, column calculations, or anything else dynamic © 2006 Adam Machanic Summary Think of the database as a shared resource that the application happens to use Design encapsulation into your data access methodology Avoid the temptation to make things overly “flexible” Consistent interfaces lead to inexpensive maintenance going forward © 2006 Adam Machanic