2. #SQLSatATL 2
Kellyn Pot’Vin-Gorman
Technical Intelligence Manager for the Office of CTO,
Delphix
• Multi-platform DBA, (Oracle, MSSQL, MySQL, Sybase,
Postgres…..)
• Oracle ACE Director, (Alumni)
• Oak Table Network
• APEX Women in Technology Award, CTA 2014
• STEM education with Raspberry Pi and Python
• Liaison for Denver SQL Server User Group
• Rocky Mountain Oracle User Group President
• Author, blogger, (http://dbakevlar.com)
5. #SQLSatATL 5
The Why
• Its interesting…to me, at least.
• VM was an issue, so moved
everything to the cloud.
• Two major players in the
database landscape.
• Good apples to “apfel”
comparison.
7. #SQLSatATL 7
FILLFACTOR is a setting for indexes in SQL Server. When you
create or rebuild an index, you can tell SQL Server what
percentage of each 8K data page used in the “leaf” level of the
index it should fill up.
Fill Factor in SQL Server
8. #SQLSatATL 8
PCT Increase in Oracle
PCTFREE is a block storage parameter used to specify how much
space should be left in a database block for future updates. For
example, for PCTFREE=10, Oracle will keep on adding new rows to a
block until it is 90% full. This leaves 10% for future updates (row
expansion). This defaults to 10% for indexes, but can be adjusted via
a index rebuild.
11. #SQLSatATL 11
Fragmentation Doesn’t Exist in Oracle Indexes
In What Case Would You Rebuild?
• Significant # of logically deleted index nodes.
• Inefficient number of gets per access
So yes, there are times and situations you need to
rebuild.
The goal here is to see where each platform
performs better than the other.
12. #SQLSatATL 12
Test Case
• Create a table with three columns and two indexes.
• Insert, update and delete different amounts of data.
• check the storage of our index and any
fragmentation, storage anomalies.
• Repeat
• Check the storage repeatedly to see how it has
changed- page splits in SQL Server, leaf block splits
in Oracle
13. #SQLSatATL 13
Goal
1. Inspect the differences and similarities of
indexing in both platforms
2. The pros and cons of how index data is stored
and used in the database platforms.
http://dbakevlar.com/2017/04/oracle-sql-server-index-comparison/
15. #SQLSatATL 15
Oracle Objects
CREATE TABLE ORA_INDEX_TST
(
C1 NUMBER NOT NULL
,C2 VARCHAR2(255)
,CREATEDATE TIMESTAMP DEFAULT CURRENT_TIMESTAMP)
;CREATE INDEX PK_INDEXPS ON ORA_INDEX_TST (C1);
CREATE INDEX IDX_INDEXPS ON ORA_INDEX_TST (C2);
ALTER TABLE ORA_INDEX_TST ADD CONSTRAINT OIT_PK
PRIMARY KEY(C1) USING INDEX PK_INDEXPS;
ALTER INDEX IDX_INDEXPS REBUILD PCTFREE 90 INITRANS 5;
ALTER INDEX PK_INDEXPS REBUILD PCTFREE 90 INITRANS 5;
16. #SQLSatATL 16
Oracle Support Objects
CREATE SEQUENCE C1_SEQ START WITH 1;
CREATE OR REPLACE TRIGGER C1_BIR
BEFORE INSERT ON ORA_INDEX_TST
FOR EACH ROW
BEGIN
SELECT C1_SEQ.NEXTVAL
INTO :new.C1
FROM DUAL;
END;
/
17. #SQLSatATL 17
Insert 7 Rows to Fill One Oracle Block
INSERT INTO ORA_INDEX_TST (C2, CREATEDATE)
VALUES (dbms_random.string('A', 200), SYSDATE);
INSERT INTO ORA_INDEX_TST (C2, CREATEDATE)
……
……
INSERT INTO ORA_INDEX_TST (C2, CREATEDATE)
VALUES (dbms_random.string('F', 200), SYSDATE);
INSERT INTO ORA_INDEX_TST (C2, CREATEDATE)
VALUES (dbms_random.string('G', 200), SYSDATE);
COMMIT;
18. #SQLSatATL 18
Check the Block
SQL> ANALYZE INDEX PK_INDEXPS VALIDATE STRUCTURE;
SQL> SELECT LF_BLKS, LF_BLK_LEN, DEL_LF_ROWS,USED_SPACE, PCT_USED
FROM INDEX_STATS where NAME='PK_INDEXPS';
LF_BLKS LF_BLK_LEN DEL_LF_ROWS USED_SPACE PCT_USED
---------- ---------- ----------- ---------- ----------
1 7924 0 1491 19
As expected- 1 leaf block for the seven
rows.
19. #SQLSatATL 19
Adjust Index and Then Insert 8th Row
ALTER INDEX IDX_INDEXPS REBUILD PCTFREE 90
INITRANS 5;
Yes, we’ve just adjusted the pctfree to 90%!
Consider what this will do to our index storage now that we’ve
rebuilt this allowing for only 10% usage in each block.
Insert the 8th row:
INSERT INTO ORA_INDEX_TST (C2, CREATEDATE)
VALUES (dbms_random.string(‘H', 200), SYSDATE);
20. #SQLSatATL 20
After Change to Pct Free
SQL> ANALYZE INDEX PK_INDEXPS VALIDATE STRUCTURE;
SQL> SELECT LF_BLKS, LF_BLK_LEN, DEL_LF_ROWS,USED_SPACE,
PCT_USED FROM INDEX_STATS where NAME='PK_INDEXPS';
LF_BLKS LF_BLK_LEN DEL_LF_ROWS USED_SPACE PCT_USED
---------- ---------- ----------- ----------
8 8229 0 2369 32
22. #SQLSatATL 22
SQL Server Objects
CREATE TABLE SQL_INDEX_TST (c1 INT NOT NULL,
c2 CHAR (255),
createdate DATETIME NOT NULL DEFAULT GETDATE());
CREATE INDEX CL2_INDEX_TST ON SQL_INDEX_TST(C2);
GO
ALTER TABLE SQL_INDEX_TST
ADD CONSTRAINT PK_CLINDX_TST PRIMARY KEY NONCLUSTERED (c1);
24. #SQLSatATL 24
Insert 7 Rows to Fill up Initial SQL Server Page
INSERT INTO SQL_INDEX_TST(c1,c2) VALUES (1, 'a');
INSERT INTO SQL_INDEX_TST(c1,c2) VALUES (2, 'a');
INSERT INTO SQL_INDEX_TST(c1,c2) VALUES (3, 'a');
INSERT INTO SQL_INDEX_TST(c1,c2) VALUES (4, 'a');
INSERT INTO SQL_INDEX_TST(c1,c2) VALUES (6, 'a');
INSERT INTO SQL_INDEX_TST(c1,c2) VALUES (7, 'a');
GO
25. #SQLSatATL 25
Alter Index Fillfactor and Insert 8th Row
ALTER INDEX CL_INDEX_TST ON dbo.SQL_Index_tst
REBUILD WITH (FILLFACTOR = 10);
GO
Now insert the 8th row in:
INSERT INTO SQL_INDEX_TST(c1,c2) VALUES (8, 'a');
GO
26. #SQLSatATL 26
Check Statistics and Page Data on Index
SELECT
OBJECT_SCHEMA_NAME(ios.object_id) + '.' +
OBJECT_NAME(ios.object_id) as table_name,
i.name as index_name, leaf_allocation_count,
nonleaf_allocation_count
FROM sys.dm_db_index_operational_stats(DB_ID(),
OBJECT_ID('dbo.SQL_INDEX_TST'),NULL, NULL) ios
INNER JOIN sys.indexes i ON i.object_id =
ios.object_id AND i.index_id = ios.index_id;
29. #SQLSatATL 29
Data Loads into Oracle
SQL> Begin
For IDS in 1..1000000
Loop
INSERT INTO ORA_INDEX_TST (C2, CREATEDATE)
VALUES (dbms_random.string('X', 200),
SYSDATE);
Commit;
End loop;
End;
/
30. #SQLSatATL 30
Check Data and Delete Data
SQL> select count(*) from ora_index_tst;
COUNT(*)
----------
1000008
SQL> delete from ora_index_tst
where c2 like '%200%';
437 rows deleted.
SQL> commit;
Commit complete.
10% PCT Free- Time Elapsed 2 minutes, 12 seconds
90% PCT Free- Time Elapsed 7 minutes, 3 seconds
31. #SQLSatATL 31
Resulting Index Fragmentation and Storage
SELECT LF_BLKS, LF_BLK_LEN, DEL_LF_ROWS,USED_SPACE, PCT_USED FROM
INDEX_STATS;
35. #SQLSatATL 35
SQL Server Insert
declare @id int
select @id = 9 --already inserted 8 rows
while @id >= 0 and @id <= 1000000
begin
insert into sql_index_tst (c1,c2) values(@id,
'DKUELKJ' + convert(varchar(7), @id))
select @id = @id + 1
end
Default Fill Factor- Elapsed Time: 4 minutes, 43 seconds
10% Fill Factor- Elapsed time: 23 minutes, 18 seconds
36. #SQLSatATL 36
Check Page Splits in SQL Server
SELECT
OBJECT_SCHEMA_NAME(ios.object_id) + '.' +
OBJECT_NAME(ios.object_id) as table_name
,i.name as index_name
,leaf_allocation_count
,nonleaf_allocation_count
FROM sys.dm_db_index_operational_stats(DB_ID(),
OBJECT_ID('dbo.SQL_Index_tst'),NULL, NULL) ios
INNER JOIN sys.indexes i ON i.object_id = ios.object_id
AND i.index_id = ios.index_id;
44. #SQLSatATL
Supporting Features
• Created Sequence for PK on C1 column
• Created Trigger to insert next value in C1 on insert.
• The % Threshold set to 20
• No compression
• Loaded from my original table ORA_INDEX_TST
47. #SQLSatATL
IOT Vulnerabilities
SQL> SELECT 'Chained or Migrated Rows =
'||value
FROM v$sysstat
WHERE name = 'table fetch continued
row';
Chained or Migrated Rows = 73730
48. #SQLSatATL
Findings
C2 column has significant data and without C1, has a
difficult time for access.
• Disable trigger for sequence and then load table
with simplified data, then rebuild.
• ALTER TABLE ORA_IOT_TST REBUILD;
51. #SQLSatATL
So PCT Free
As discussed, Pct Free is how much free is to be left
at the end of a block…90%...hmm…
52. #SQLSatATL
Comparisons- Pct Free Vs. Fill Factor
10% Fill Factor in SQL Server and 1 million insert: Elapsed time: 23
minutes, 18 seconds
90% PCTFree in Oracle and 1 million insert: 7 min, 12 seconds
100% Fill Factor in SQL Server and 1 million insert: Elapsed Time: 4
minutes, 43 seconds
0% PCTFree in Oracle and 1 million insert: 1 min, 8 seconds
REBUILD of the Oracle IOT to make it 90% free in each block? Elapsed
Time: 8 hrs, 21 minutes, 12 seconds
54. #SQLSatATL
Clustered Index in SQL Server
• Data is physically sorted in clustered index by
default.
• Optimizer usage specific- clustered index seek
• Works best with sequential data, identity columns
and order dates.
• Option to randomize the writes on the index can
deter from hot spots.
55. #SQLSatATL
SQL Server Negatives
• Heavily vulnerable to fragmentation over standard
Oracle indexing.
• Last Page Insert Latch Contention- not an issue in
Oracle.
• Subject to hotspots, (as discussed.)
• Page Splits- hit performance HARD, especially
tran log.
• Fillfactor is hit or miss config in some systems.
56. #SQLSatATL
Summary- Clustered Index
Clustered Index:
• Less overhead during transactional processing for
inserts, updates and deletes
• Improved performance on queries of data to be sorted
in sequential order.
• Similar performance for complex queries and less sort
temp usage.
• Clustered Indexes are common place, IOTs have limited
use case.
57. #SQLSatATL
Summary: IOT
• Will require more maintenance if the IOT experiences
high processing including inserts, updates and deletes.
• DBCC rebuilds of a clustered index uses less resources
and doesn’t impact the transaction log as it does
Oracle’s rollback and archive log.
• It was easier to build the table with a high pct free
storage configuration and then do an insert of the
data, then drop the old table than to do an “alter
move” command.
These are just basic storage features we’re testing, so no concerns about using either of these. Both are hosted in the cloud.
This was based off research done between Paul Randall’s work, which then created interest for me to compare to Oracle’s Richard Foote. Both focus on index performance and I was able to adapt their work to perform a comparison.
It isn’t a true apple to apple comparison, but I do think it helps to understand the differences with respect to each platform.
This is based off two major players in the Database realm, (I may introduce MySQL or another database to make it more interesting in the future.) but had fun moving it from my local VMs to Amazon and Azure. My Amazon environment is busy being used for a huge demonstration build for my Oracle Open World talk, so I had to scour my index play from it to ensure I didn’t impact what my partner from another company was building.
Main translations that will be required for this session
This is what all DBAs think of when we hear IOT. Not Internet of Things, but Index Organized Table. The reuse of acronyms will be the death of us all.
It’s the closest thing to what SQL Server uses for it’s initial index on any table. Where data sorts are almost expected on the first, indexed column, Oracle invests highly on temp “tablespace”, (similar to filegroups in SQL Server) which performs all sorts and hashes, etc. that won’t fit inside the PGA, (Process Global Area) of the SGA, (System Global Area) which are separated areas of memory to perform tasks. SQL Server uses a Temp database to perform similar processing.
I’ll skip over the next one, as we’ll dig into these in a moment.
Although Oracle and SQL Server has Sequences, I used older terminology and syntax here and I wanted to point that out, as with dbms_random, which is a built in package, (group of procedures, etc.) to populate data in Oracle.
A page and a block is very similar and then we have the AWR and DMVs, which are very similar, but Oracle saves off aggregates of this performance data long term, 1 hr, 1 week, 30 days, 1 year and DMVs of course, have some data that is only cached and must be called with functions.
The default for Oracle versions 11g and DB12c is 10%
Oracle rarely would recommend you change this, but many old school DBAs still mess with this setting and I’ve come across many databases that have been upgraded over the years that still have object with odd settings for individual objects, (tables and indexes.)
The Page Splits/sec counter is one of the "piece of string" counters for which no absolute value should be assumed a breaking point for performance challenges.
The counter can vary depending on table size, density, index depth, workload and workload type.
Page Splits are an occurance on clustered indexes, which are an advanced feature for indexing as a whole and a standard feature for SQL Server.
A split happens, as shown here, when there isn’t enough room in a page and the data needs to write to the beginning of a new page.
SQL Server needs to hold a latch for an extended period of time to alocate the new latch, copy data from the old page to the new page and then write the new data to the new page.
SQL Server can also take additional latches on the intermediate index pages while in wait.
This is the reason that rebuilds of indexes is still a common task in MSSQL.
This is a higher latency wait when concurrency is added to the mix.
From the power dynamic mgnt view, dm_db_index_usage, we can locate when there are indexes that are fragmented and impact performance in MSSQL.
Oracle leaves "dead" index nodes in the index when rows are deleted.
While rebuilding indexes is a topic that’s heavily debated, there are some poor coding choices or application processing that can offer a reason for index rebuilds.
You’ll come across an index that’s space consumption is larger than the table is sources from.
This is rare though and as I said, it can be resolved by fixing the code or the application code.
We’ll do this a number of times as we simulate poor processing that would cause issues in page splits, data storage and impact to performance.
Create table, primary key on C1 to be populated by a sequence and trigger and index on C2
Create Sequence and Trigger to insert before each row.
Insert in 7 rows to fill up one block.
Because I have a sequence and trigger in place, I only need to add the random data, 200 char and the current date.
Notice the fillfactor is now 10 and insert in one more row…
Insert 1 million rows
This is the first 8 rows from the initial test and the 1 million from the second test.
Now delete rows where c2 includes the value of 200
Notice our leaf blocks now and our used space.
Our table has grown substantially from where we’ve started with a number of load processes and transactions to create fragmentation, storage changes, etc.
And we show, we’ve deleted the rows we desired.
Let’s load another 1 million rows into our Azure table with the clustered index.
Thanks to Paul Randall for much of the original research that I was able to then build comparisons to Richard Foote’s research on the Oracle side.
Notice the inserted “junk data” we’re using for our examples. Using our IOT, we’ll remove rows from the middle of the table.
Vs. an index rebuild, we need to use a table rebuild statement here, since the INDEX IS a TABLE, as demonstrated here.
Considering the amount of rows and not just the rows need to be compressed, but also sorted for an IOT, this will take some time.