• No results found

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

N/A
N/A
Protected

Academic year: 2021

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

Copied!
42
0
0

Loading.... (view fulltext now)

Full text

(1)

Common mistakes

developers make in

SQL Server

“Amateurs work until they get it right. Professionals work

until they can't get it wrong.”

(2)

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

(3)

Agenda

Faster hardware

Row By Agonizing Row (pronounced Ree-bar)

Bad indexing

Index misuse

Triggers

(4)

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

(5)

FASTER HARDWARE

(6)

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.

(7)

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.

(8)
(9)
(10)
(11)
(12)
(13)
(14)

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

(15)

ROW BY AGONIZING ROW

(16)

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.

(17)

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

(18)

Row By Agonizing Row

(19)

Row By Agonizing Row

SELECT a.RowNum AS RowNum_A,

b.RowNum AS RowNum_B

FROM TableA AS a,

TableB AS b

(20)

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!

(21)

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/

(22)

BAD INDEXING

(23)

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

(24)
(25)

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

,

(26)
(27)
(28)
(29)

INDEX MISUSE

(30)

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

(31)
(32)
(33)
(34)
(35)

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

(36)

TRIGGERS

(37)

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

(38)

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

(39)

INDETERMINISTIC FUNCTIONS

(40)

Simple indeterministic function

select

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

(41)

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

(42)

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

References

Related documents

The MEP must provide the registry manager with the required metering information for each metering installation the MEP is responsible for, and update the registry metering records

Most importantly for our purposes, the three thinkers Anderson aligns himself with here (Lukacs, Gramsci and Sartre) are precisely those whom Williams (1972) will describe as

3.3.3.4 Proses 5.0 Proses Pembayaran Pada diagram rinci sistem proses 5.0 tentang pembayaran ini yang mengakses adalah operator yang tadinya telah didaftarkan oleh admin,

Identification of a Notched Kernel Gene Associated with Pre-Harvest Sprouting Using Oryza glumaepatula Introgression Lines in Rice.. Sobrizal 1* and Atsushi Yoshimura 2 Diterima

(Wikipedia) As far as Unilever Pakistan is concerned, the culture of the company had a great impact upon the environment in which it is operating. Unilever claims that it is a

Treatment differences in terms of R levels and transition frequency are mainly driven by the adaptation process: figure 3 shows that groups which transition to the efficient

The UK needs a new aviation strategy that is based on more realistic forecasts of demand, and one that creates a better balance between environmental impact and economic benefits..

53 Figure 5.9 Distribution of profits and losses for the RSLN-2 and Vasicek models 53 Figure 5.10 Distribution of cumulative hedging error at maturity with daily re-.. balancing for