42
Common mistakes developers make in SQL Server “Amateurs work until they get it right. Professionals work until they can't get it wrong.”

Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

  • Upload
    others

  • View
    0

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Common mistakes

developers make in

SQL Server“Amateurs work until they get it right. Professionals work

until they can't get it wrong.”

Page 2: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Who am I?

• Self-employed

• 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95.

• Long time consultant

• 15 years, Visual Basic 6.0, SQL Server 4.21 to 2008R2.

• Employed

• 3 years, SQL Server 2000 to 2008R2 and Denali (2011?).

• MVP – Microsoft Valuable Professional

• SQL Server since 2009.

• Active on several forums as Peso, SwePeso or Pesomannen

• www.sqlteam.com

• www.sqlservercentral.com

• msdn.microsoft.com

Page 3: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Agenda

• Faster hardware

• Row By Agonizing Row (pronounced Ree-bar)

• Bad indexing

• Index misuse

• Triggers

• Indeterministic functions

Page 4: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Before we start

• Before you make any change on a production SQL Server, be

sure you test it first in a test environment

• NO EXCEPTIONS!

• I mean it!

• Really!

• No kidding

• I wouldn’t lie to you

• You’d be crazy not listening to this advice

• Never forget, DBAs and developers are the protectors of the

organization’s data

• You took this oath when you accepted the job

Page 5: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

FASTER HARDWARE

The golden bullet

Page 6: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Faster hardware

• You can throw faster hardware at a problem if you want but

don't be surprised if it doesn't actually help much.

• True performance can only be found in the code and the

design of the database.

• Let's stop and think about faster hardware to do the same

thing

• Let's say the CPU speed and disk throughput is doubled.

• That would mean a 2 hour query might drop to 1 hour.

• Rewriting the old code could drop the query time to 3 seconds.

Page 7: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Faster hardware

• More cores mean more

queries can request

massive numbers of

locks simultaneously and

the badly written

queries need many locks

that may cause

performance to

deteriorate under faster

hardware.

• SQL Server spends more

time waiting and less

time working.

Page 8: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Faster hardware

Page 9: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Faster hardware

Page 10: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Faster hardware

Page 11: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Faster hardware

Page 12: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Faster hardware

Page 13: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Faster hardware

Page 14: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Faster hardware

Query Index Parallellism Reads CPU Duration

Old query No No 1,805,000 216.00 217.00

Old query No Yes 1,845,000 221.00 113.00

Old query Yes No 59,000 3.00 4.00

Old query Yes Yes 59,000 4.00 3.00

New query No No 120 0.10 1.00

New query Yes No 120 0.05 1.00

Page 15: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

ROW BY AGONIZING ROW

Loops, cursors and triangular joins

Page 16: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Row By Agonizing Row

• Phrased by Jeff Moden

• Good friend and fellow SQL Server MVP from SQLServerCentral.

• http://www.sqlservercentral.com/articles/T-SQL/61539/

• Learn to recognize Triangular Joins

• They appear in the SELECT list as correlated subqueries usually with a stand-alone inequality of some sort

• They can also appear in WHERE clauses with the same type of standalone inequality.

• Not all Triangular Joins are bad

• With some restraint and the right criteria, Triangular Joins can be used for some pretty remarkable things

• Make finite schedules

• Do high speed dupe checks

• But, you've really got to be careful.

• Improperly written Triangular Joins are worse than Cursors or While Loops and can bring a CPU and Disk System right to it's knees.

• Watch out for "Hidden RBAR"

Page 17: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Row By Agonizing Row

• Many folks think that set-based programming means one of two things

• It simply doesn't have a Cursor or a While Loop.

• It's all done in a single query.

• Both of those are very bad misconceptions as to what set based programming is

• Touch each row of data only once if you can and as few times as possible if you can't.

• A loop (cursor)

• Works row-by-agonizing-row.

• Overrides the natural abilities of the optimizer.

• Only operates on a single row instead of a set of rows.

• Most explicit loops are not set based programming and they just crush performance.

Page 18: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Row By Agonizing Row

Cursor-based solution Set-based solution

Page 19: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Row By Agonizing Row

SELECT a.RowNum AS RowNum_A,

b.RowNum AS RowNum_B

FROM TableA AS a,

TableB AS b

WHERE a.RowNum <= b.RowNum

Page 20: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Row By Agonizing Row

• Good examples from the Phil Factor Speed Phreak competitions

• http://ask.sqlservercentral.com/questions/92/the-subscription-list-sql-problem

• Cursor 780 seconds (13 minutes).

• Set-based 0.3 seconds - 2,500 times faster!

• http://ask.sqlservercentral.com/questions/826/the-fifo-stock-inventory-sql-problem

• Cursor 2,400 seconds (40 minutes).

• Set-based 1.3 seconds – 1,800 times faster!

• http://ask.sqlservercentral.com/questions/6529/the-ssn-matching-sql-problem

• Cursor 4,000 – 4,500 seconds (70 - 75 minutes).

• Set-based 0.5 seconds – 9,000 times faster!

• SQLCLR 0.4 seconds – 11,000 times faster!

Page 21: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Row By Agonizing Row

• Kathi Kellenberger, former SQL Server MVP, provides in-depth

descriptions and analyses of the different solutions here

• http://www.simple-talk.com/sql/performance/writing-efficient-

sql-set-based-speed-phreakery/

• http://www.simple-talk.com/sql/performance/set-based-speed-

phreakery-the-fifo-stock-inventory-sql-problem/

• http://www.simple-talk.com/sql/performance/ssn-matching-

speed-phreakery/

Page 22: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

BAD INDEXING

The hidden performance crusher

Page 23: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Bad Indexing

SELECT ent.entEngagementID

,thd.thdPlaceOfSale

,COUNT(*)

FROM dbo.Engagement ent

INNER LOOP JOIN dbo.TransactionHead thd ON thd.entEngagementID

= ent.entEngagementID

INNER JOIN dbo.EngagementParameter epr ON epr.tepTypeEngagementParameterID

= (SELECT tepTypeEngagementParameterID

FROM TypeEngagementParameter

WHERE tepCode = 'StorePeriodLen')

AND DATEDIFF(MM, DATEADD(MM, -CONVERT(INT,eprParameterValue),

GETDATE()), thd.thdTransactionDate) > 0

AND epr.tetTypeEngagementID = ent.tetTypeEngagementID

INNER JOIN dbo.TypeTransactionHead tth ON tth.tthTypeTransactionHeadID

= thd.tthTypeTransactionHeadID

AND tth.tthCode IN ('Purchase', 'Return', 'Mixed')

GROUP BY ent.entEngagementID

,thdPlaceOfSale

Page 24: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Bad Indexing

Page 25: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Bad Indexing

SELECT ent.entEngagementID,

thd.thdPlaceOfSale,

COUNT(*)

FROM dbo.TypeEngagementParameter AS tep

INNER JOIN dbo.EngagementParameter AS epr ON epr.tepTypeEngagementParameterID

= tep.tepTypeEngagementParameterID

INNER JOIN dbo.Engagement AS ent ON ent.tetTypeEngagementID

= epr.tetTypeEngagementID

INNER JOIN dbo.TransactionHead AS thd ON thd.entEngagementID

= ent.entEngagementID

INNER JOIN dbo.TypeTransactionHead AS tth ON tth.tthTypeTransactionHeadID

= thd.tthTypeTransactionHeadID

AND tth.tthCode IN ('Purchase', 'Return', 'Mixed')

WHERE thd.thdTransactionDate >= DATEADD(MONTH, DATEDIFF(MONTH, '19000101',

GETDATE()) - CONVERT(INT, epr.eprParameterValue), '19000201')

AND tep.tepCode = 'StorePeriodLen'

GROUP BY ent.entEngagementID,

thdPlaceOfSale

Page 26: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Bad Indexing

Page 27: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Bad Indexing

Page 28: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Bad Indexing

Page 29: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

INDEX MISUSE

O Index, Where Art Thou?

Page 30: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Index misuse

-- Query 1

SELECT *

FROM dbo.TestIndexes

WHERE YEAR(MyDate) = 2005

-- Query 2

SELECT *

FROM dbo.TestIndexes

WHERE MyDate >= '20050101'

AND MyDate < '20060101'

-- Query 3

SELECT *

FROM dbo.TestIndexes

WHERE CONVERT(CHAR(4), MyDate, 112) = '2005'

Page 31: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Index misuse

Page 32: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Index misuse

Page 33: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Index misuse

Page 34: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Index misuse

Page 35: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Index misuse

Query Records Scan Count Logical Reads CPU Duration

Query 1 1,000 1 5 0 0

Query 2 1,000 1 2 0 0

Query 3 1,000 1 5 0 0

Query 1 10,000 1 25 0 3

Query 2 10,000 1 2 0 0

Query 3 10,000 1 25 0 8

Query 1 100,000 1 226 31 30

Query 2 100,000 1 3 0 0

Query 3 100,000 1 226 78 81

Query 1 1,000,000 1 2,250 312 300

Query 2 1,000,000 1 12 0 1

Query 3 1,000,000 1 2,250 811 819

Query 1 10,000,000 17 22,679 3,620 295

Query 2 10,000,000 1 85 0 180

Query 3 10,000,000 17 22,679 10,329 739

Page 36: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

TRIGGERS

To batch or not to batch?

Page 37: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Triggers

Create TRIGGER [dbo].[Fault_Parked_UPDATE] ON [dbo].[Detail]

FOR INSERT, UPDATE

AS

Declare @CalliD Varchar(8), @Park1Start datetime,@Park1End datetime, @Park1 INT, @TotalParkedTime INT

Declare @FaultEnd datetime, @FaultTotal INT, @FaultMinusParked INT, @FaultStart datetime

Select @callid=Callid FROM inserted WHERE isdate(FaultStart)=1 and isdate(FaultEnd)=1

IF @Callid IS NOT NULL Begin

Select @Park1Start = CASE WHEN ISDATE(@Park1Start)= 1 THEN Cast([ParkedDate1]+' '+[ParkedTime1] as datetime)

ELSE CAST('1900-01-01 00:00:00' as DateTime) END

from detail

Where callid = @Callid

Select @Park1End = CASE WHEN ISDATE(@Park1End)= 1 THEN Cast([UnParkedDate1]+' '+[UnParkedTime1] as datetime)

ELSE CAST('1900-01-01 00:00:00' as DateTime) END

from detail

Where callid = @Callid

Select @Park1 = datediff(ss,@Park1Start ,@Park1End)/60

Select @TotalParkedTime = @Park1

Select @FaultStart = Cast([FaultStart]+' '+[FaultStartTime] as datetime) from detail Where callid = @Callid

Select @FaultEnd = Cast([FaultEnd]+' '+[FaultEndTime] as datetime) from detail Where callid = @Callid

Select @FaultTotal = datediff(ss,@FaultStart ,@FaultEnd)/60

Select @FaultMinusParked = @FaultTotal - @TotalParkedTime

UPDATE CallLog

set Park1 = @Park1, TotalParkedTime = @TotalParkedTime,

FaultMinusParked = @FaultMinusParked, FaultTotal = @FaultTotal

Where calllog.CallID = @CallID

END

Page 38: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Triggers

CREATE TRIGGER dbo.Fault_Parked_UPDATE

ON dbo.Detail

FOR INSERT,

UPDATE

AS

;WITH cteValid(CallID, Park1, FaultTotal)

AS (

SELECT CallID,

CASE

WHEN Park1End > Park1Start AND ISDATE(ParkedDate1) = 1 THEN DATEDIFF(SECOND, Park1Start, Park1End) / 60

ELSE 0

END AS Park1,

DATEDIFF(SECOND, FaultStart, FaultEnd) / 60 AS FaultTotal

FROM (

SELECT CallID,

ParkedDate1,

CAST(ParkedDate1 + ' ' + ParkedTime1 AS DATETIME) AS Park1Start,

CAST(UnParkedDate1 + ' ' + UnParkedTime1 AS DATETIME) AS Park1End,

CAST(FaultStart + ' ' + FaultStartTime AS DATETIME) AS FaultStart,

CAST(FaultEnd + ' ' + FaultEndTime AS DATETIME) AS FaultEnd

FROM inserted

WHERE ISDATE(FaultStart) = 1

AND ISDATE(FaultEnd) = 1

AS d

)

UPDATE cl

SET cl.Park1 = v.Park1,

cl.TotalParkedTime = v.Park1,

cl.FaultMinusParked = v.FaultTotal - v.Park1,

cl.FaultTotal = v.FaultTotal

FROM dbo.CallLog AS cl

INNER JOIN cteValid AS v ON v.CallID = cl.CallID

Page 39: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

INDETERMINISTIC FUNCTIONS

I didn’t see that coming…

Page 40: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Simple indeterministic functionselect top(10) case abs(checksum(newid()))%4 when 0 then 0 when 1 then 1 when 2 then 2 when 3 then 3 end from sys.objects

CASE WHEN abs(checksum(newid())) % 4 = 0 THEN 0 ELSE WHEN abs(checksum(newid())) % 4 = 1 THEN 1 ELSE WHEN abs(checksum(newid())) % 4 = 2 THEN 2 ELSE WHEN abs(checksum(newid())) % 4 = 3 THEN 3 ELSE NULL END END END END

Page 41: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Advanced indeterministic function

CASE

WHEN datepart(month, dbo.fnGetOrderDate(SalesOrderID)) = 1 THEN 'Jan'

ELSE CASE WHEN datepart(month, dbo.fnGetOrderDate(SalesOrderID)) = 2 THEN 'Feb'

ELSE CASE WHEN datepart(month, dbo.fnGetOrderDate(SalesOrderID)) = 3 THEN 'Mar'

ELSE CASE WHEN datepart(month, dbo.fnGetOrderDate(SalesOrderID)) = 4 THEN 'Apr'

ELSE CASE WHEN datepart(month, dbo.fnGetOrderDate(SalesOrderID)) = 5 THEN 'May'

ELSE CASE WHEN datepart(month, dbo.fnGetOrderDate(SalesOrderID)) = 6 THEN 'Jun'

ELSE CASE WHEN datepart(month, dbo.fnGetOrderDate(SalesOrderID)) = 7 THEN 'Jul'

ELSE CASE WHEN datepart(month, dbo.fnGetOrderDate(SalesOrderID)) = 8 THEN 'Aug'

ELSE CASE WHEN datepart(month, dbo.fnGetOrderDate(SalesOrderID)) = 9 THEN 'Sept'

ELSE CASE WHEN datepart(month, dbo.fnGetOrderDate(SalesOrderID)) = 10 THEN 'Oct'

ELSE CASE WHEN datepart(month, dbo.fnGetOrderDate(SalesOrderID)) = 11 THEN 'Nov'

ELSE CASE WHEN datepart(month, dbo.fnGetOrderDate(SalesOrderID)) = 12 THEN 'Dec'

ELSE NULL

END

END

END

END

END

END

END

END

END

END

END

END

Page 42: Common mistakes developers make in SQL Server · Who am I? • Self-employed • 6 years, Visual Basic 3.0 to 6.0, Access 1.0 to 95. • Long time consultant • 15 years, Visual

Want to know more?

• Married with children

• 6 year girl, 3 year girl and 1 year boy.

• One girl to be born on May 11.

• Live outside Helsingborg

• Blog at

• http://weblogs.sqlteam.com/peterl/

• Homepage and contact

• http://www.developerworkshop.net/

[email protected]

• Co-founder of PASS Scania

• http://www.pass-scania.se/

• Now part of SQLUG

• Phil Factor Speed Phreak challenges

• 3 time winner

• Another presentation

• Execution Plan basics