Thursday, October 8, 2015

What's slow on my database server?

What's slow on my database server?

A video investigating the relative performance of network, disk IO, and CPU on SQL Server.


Here is the SQL that goes with the demo.

-- Database by Doug
-- 10/8/2015
-- What's Slow Demo?

-- for database performance
-- There are 3 basic items to worry about:
-- * IO
-- * Network
-- * CPU

-- I see many people focus on them in this order:
-- 1 - CPU
-- 2 - IO
-- 3 - network

-- this demo should show that you should focus on them in this order:
-- 1 - network
-- 2 - IO
-- 3 - CPU


-- part 1: network vs IO
use referencedb

SET STATISTICS IO ON

SELECT *
FROM   Person

-- about 53 seconds

-- while this runs, here's some basics about the setup:

-- SQL Instance running as a virtual machine, no idea about the storage, general purpose
-- synthetic data with reasonable data distributions
-- 1.3M records
-- average record size is about 456 bytes
-- zero fragmentation
-- total table size about 587MB
-- some bogus fields for experimentation
-- no non-clustered indexes

--CREATE TABLE [dbo].[Person](
-- [ID] [int] IDENTITY(1,1) NOT NULL,
-- [salutory] [nvarchar](15) NULL,
-- [firstName] [nvarchar](25) NULL,
-- [middleInitial] [nchar](1) NULL,
-- [lastName] [nvarchar](25) NOT NULL,
-- [nameSuffix] [nvarchar](8) NULL,
-- [email] [nvarchar](255) NULL,
-- [entryDate] [datetime] NOT NULL CONSTRAINT [DF_Person_entryDate]  DEFAULT (getdate()),
-- [lastUpdateDate] [datetime] NOT NULL CONSTRAINT [DF_Person_lastUpdateDate]  DEFAULT (getdate()),
-- [weight] [float] NULL,
-- [gender] [char](1) NULL,
-- [dateOfBirth] [date] NULL,
-- [bogusGUID] [uniqueidentifier] ROWGUIDCOL  NULL CONSTRAINT [DF_Person_bogusGUID]  DEFAULT (newid()),
-- [bogusGUID2] [uniqueidentifier] NULL CONSTRAINT [DF_Person_bogusGUID2]  DEFAULT (newid()),
-- [bogusChar] [char](100) NOT NULL CONSTRAINT [DF_Person_bogusChar]  DEFAULT ('fred'),
-- [bogusNChar] [nchar](100) NOT NULL CONSTRAINT [DF_Person_bogusNChar]  DEFAULT (N'george'),
-- CONSTRAINT [PK_Person] PRIMARY KEY CLUSTERED ( [ID] ASC)
--) ON [PRIMARY]


-- ok, so what about this?
SELECT TOP 1 ID
FROM   Person

-- one record, one value, 4 bytes
-- 0 seconds - the time for a round trip

-- so what is slow?

SELECT ID
FROM   Person
-- 1.3M records, 4 bytes each
-- about 4 seconds

SELECT ID, ID
FROM   Person
-- 1.3M records, 8 bytes each
-- about 5 seconds

SELECT bogusGuid
FROM   Person
-- 1.3M records, 16 bytes each
-- about 5 seconds


SELECT bogusGUID,
       bogusGUID2
FROM   Person
-- 1.3M records, 32 bytes each
-- about 6 seconds

SELECT 75804 * 8/1024

SELECT bogusGUID,
       bogusGUID2,
       '1234567890'
FROM   Person
-- 1.3M records, 42 bytes each
-- about  seconds

SELECT bogusGUID,
       bogusGUID2,
       '1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890'
FROM   Person
-- 1.3M records, 132 bytes each
-- about 16 seconds

SELECT bogusGUID,
       bogusGUID2,
       '1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890',
       '1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890'
FROM   Person
-- 1.3M records, 232 bytes each
-- about 27 seconds


-- keep going, and you get a graph that looks like ...

-- but you are cheating - you have all your data in memory...

-- now starve the db server for memory
  /**
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'max server memory', 256;
GO
RECONFIGURE;
GO
**/
SELECT ID
FROM   Person
-- 1.3M records, 4 bytes each
-- about 4 seconds



-- network is slower than IO
-- even with  physical IO

-- **************************************************


 /**
sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'max server memory', 2147483647;
GO
RECONFIGURE;
GO
**/

-- part 2: IO vs CPU


SELECT AVG(weight)
FROM   Person
-- 1.3M records, but only 8 bytes back
-- about 0 seconds

-- can we make it worse?
-- can we make the CPU worse?

SELECT weight
FROM   Person
-- 1.3M records, 8 bytes back per record
-- 4 seconds

SELECT MAX(weight)
FROM   Person
-- about 0 seconds

SELECT AVG(LOG(weight/1.7))
FROM     Person
-- 1.3M records, 8 bytes back
-- about 0 seconds

SELECT AVG(SQRT(LOG(weight/1.7)))
FROM     Person
-- about 0 seconds

SELECT AVG(SIN(SQRT(LOG(weight/1.7))))
FROM     Person
-- about 0 seconds

SELECT AVG(SIN(SQRT(10+3.3*LOG(weight/1.7))))
FROM     Person
-- about 1 seconds

SELECT AVG(SIN(SQRT(10+3.3*LOG(weight/1.7)))*PI())
FROM   Person
-- about 1 seconds

-- taking just the average out
SELECT (SIN(SQRT(10+3.3*LOG(weight/1.7)))*PI())
FROM   Person
-- 4 seconds

-- you can do tons of calculations, and not impact speed

-- summary: focus on items in this order
-- 1 - network
-- 2 - IO
-- 3 - CPU

-- caveats:
-- your mileage may vary
-- use your own judgement
-- this is the order in which I do investigations on a new database

-- end of what's slow

1 comment:

  1. Can you go over how you approach network and IO issues.

    ReplyDelete

Followers