Architecting Effective SQL Server Data Access Solutions

Download Report

Transcript Architecting Effective SQL Server Data Access Solutions

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