Friday, August 28, 2009
Normalization
well except for me and a few exceptional dbas I know :)
I was remembering fun times at a previous company, here's some things they did to violate normalization.
1) The EMAIL column could be used for any type of data someone wanted, but then again so could address2 and a host of others. Here's an idea people, if you name a column something specific how about only that data goes in there?
2) SSN stored as an INT. Yes, your SSN is a number but did you know that some of the SSNs start with a 0? Well they do and if you put 098005550 into an INT column guess what happens. That's right, you lose the leading 0. So, do we change the column type? oh hell no, make the software count the values in the string and append zeros to the front of the string if it is less than 8 characters.
3) Don't use foreign keys, they cause errors if you try to delete data from a table that still has data in a child table. And it's hard to delete from tables in a specific order... GAH
ok enough ranting
Normalization is good, it is your friend
If anyone from the big C is reading, this is totally not a post about your company.
--matt
dynamic table names?
If you're doing that, I assume you're trying to use it in a FROM or JOIN statement.
To accomplish it, you would have to use dynamic sql. Passing a table name in a variable won't work otherwise.
Why dynamic sql is evil!
1) You must grant privileges to underlying objects, execute on the procedure will not be sufficient
2) The query plan SQL stores will not be appropriate for every execution of the procedure. So you either have a crap plan or SQL has to recompile.
3) They are a giant PITA to troubleshoot. Inevitably, you end up pulling the dynamic statements out of the proc and running them manually to find the problem.
Avoid dynamic SQL like you would a rabid animal
--matt
Thursday, August 20, 2009
SQL vs Oracle - temp tables
SQL vs Oracle
I ran into this a week ago and have not been completely happy with the Oracle solution. I am not saying that it doesn’t work, but it just seems like there is a better way. (oh look, there’s sql server doing it in a better way)
Here’s the skinny
Temporary tables.
I have been known to throw data sets around inside of a stored proc and SQL Server has this sweet little bit of trickery that lets me have a table variable. Oh yes friends, a variable that acts like a table. I can insert, update, delete and select data from it. It resides in memory and will usually never be written to disk.
Ok, quick history lesson for those of you not following. In SQL server, you can have temp tables and table variables. Temp tables are ALWAYS written to disk. Table variables are only written to disk if there is not enough memory to hold the data. So think about this, if I read from a few tables and put the data into a temp table and then read it back out, what am I doing? Read, write, then read. Your disks are just a spinnin! With a table variable (praise Bob!) it sits in memory, is only viable for the scope of the procedure and I am not spinning disks. Super groovy.
(just a personal opinion, but if you are returning so much data that your table variable needs to write to disk… maybe you should rethink what you are trying to do)
Back on topic.
So what do we have in Oracle land that can do the same thing you ask? Well in a word, nothing. The only alternative I can find is the Global Temporary Table. This is a physical table space created once and it sits there for you to use. Read from the disk, write back to the disk and read again. Ugh. It does have a nice feature though, it keeps session data separate. Session 1 can insert rows and retrieve them without the data being mangled and merged with data from sessions 2-900. Kind of nice, but it still writes to disk.
Coding procedures, especially ones where I have to nab a dataset and then join against it, is super easy when using table variables and the impact is pretty minimal. While global temp tables are not hard to use, they do have some tricksy properties.
If you are using a global temp table you need to be aware of the two different settings.
The basic syntax is:
CREATE GLOBAL TEMPORARY TABLE SOMETABLE ( SOMEID NUMBER, SOMEDATA VARCHAR2 (256) )
The next part if the syntax can be one of two settings
ON COMMIT DELETE ROW – This indicates the data should be deleted at the end of the transaction
Or
ON COMMIT PRESERVE ROWS – This indicates the data should be deleted at the end of the session
I personally use the PRESERVE since I use the temp table multiple times in a session / procedure and not just in one transaction.
In contrast, the table variable holds my data for the session.
I really do prefer the table variable to temp tables, writing data back to disk after I just got it out of there seems wrong to me.
Oh, here is the syntax for creating a table variable
Declare @SomeTable Table (SomeID INT, SomeData Varchar(256) )
--matt
Fun stuff
The movie was ok, as long as you don't expect much of a plot or acting.
The book however was enjoyable and I recommend it with a 3 out of 5 stars.
Oracle points
There are two things in procedure creation that I wish SQL Server would do.
1) CREATE OR REPLACE - this handy little statement basically does a create or alter! No more looking to see if the procedure exists and then Drop / Create statements.
2 Probably my favorite Oracle coding trick so far! For variables in your procedures, you can assign a table.column data type instead of hard coding it.
Oracle -
P_SOMEVARIABLE IN SCHEMA.TABLE.COLUMN%TYPE
In SQL Server, we have to make sure the types in the procedures match up with what we code in the table. I know I'm not the only one who has made a VARCHAR (200) column and set the variable in the INSERT procedure to VARCHAR (100).
Nice work Oracle, that's two super sweet little items that actually help!
Wednesday, August 19, 2009
Scale out SQL Server
An interesting question was posed to me today. What's a good strategy for scaling out SQL Server?
My answer: It kind of depends on your situation, one of the best ways is to have hardware (active / passive ) clusters at multiple sites and replicate between them. Here are a few scale out options (in no particular order).
1. Peer to Peer Replication - Multiple servers across the planet can be used for read/write access and all of the data can be replicated to each server in the group. This is great if every server needs to have all of your data, you can scale that back a little and replicate only that data relevant to the site.
2. One great way is to separate out processes. OLTP goes to this server, ADHOC / Reporting goes to another server, batch processes go to a third and a fourth server is set apart for data warehouse staging. You can accomplish this with log shipping (still viable in my opinion) or one way replication. The key is to get the extra processing stuff that doesn't need to be on your OLTP server off onto a secondary system. Reduce the traffic your real time app needs to contend with.
3. Horizontal partitioning - There are plenty of articles out there about it, but simply put you break apart your data into manageable chunks and place it on different database servers.
I am not aware of any practical way to have Active Active SQL databases. Unless you are partitioning your data to different databases and then putting them in a 2 way cluster. That scares the willies out of me though, since when you fail one of the boxes over you will be putting the load of both databases onto one machine.
Fight the stupid
Developer, "So, I want to store a bit string for a user. This bit string will define what web forms the user has access to. How do we store that in the database?"
DBA, "We won't be storing it that way. If you want to define relationships between a table of users and a table of web forms with permissions and dates and levels and whatever, that would be great. We will not be storing a bit string."
Developer, "But, it's easier for me to do it that way!"
DBA, "Ok, how about this. If you store a bit string I get to create a job that runs every other tuesday changing the 3rd bit of your string to the letter Q and deleting everything after the 9th bit. How does that work for you?"
Developer, "Well no, that would be bad"
DBA, "Yes, so is your idea. "
Yeah, this really happened.
I think I'll take a nap now.
--matt
Fight the stupid
Stored procedure fight with Oracle
Create Procedure dbo.SomeTableSelect
( @SomeID INT ,
@SomeValue Varchar(50)
)
as
Select SomeID,SomeValue,SomeDate
From dbo.SomeTable
Where SomeID = @SomeID
and SomeValue = @SomeValue
Pretty simple and easy to do right? Well transfer that to Oracle. Guess what, it doesn't work that way! In Oracle, you can pass in parameters but you have to use a cursor to get back the data. What's really fun, is if you want to run the procedure, you have to declare a cursor so that the cursor inside the procedure can write data out. GAHH!
Oracle code:
CREATE OR REPLACE PROCEDURE SOMETABLESELECT
(
P_SOMEID IN NUMBER,
P_SOMEVALUE IN VARCHAR2,
P_OUT_REF OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN P_OUT_REF FOR
SELECT SOMEID, SOMEVALUE, SOMEDATE
FROM SOMETABLE
WHERE SOMEID = P_SOMEID
AND SOMEVALUE = P_SOMEVALUE;
END;
Some things to remember in Oracle
1) Oracle is case sensitive! Always name your objects with ALL CAPS, it will not find the procedure SomeTableSelect, no matter how much you yell at it that the stupid thing is right there.
2) Always use a BEGIN and END, you have to actually or the syntax will be invalid.
3) Remember your ";" this ends commands in Oracle and you need it.
4) Oracle will let you create a procedure that is completely invalid, yipee.
Oracle doesn't actually hate to return data, but it seems to assume that you will only ever ask for a single row. Many examples of how to return data have you putting the result set into a group of out output variables, which means you could only return a single row.
In conclusion, I think SQL Server wins this round. The ability to extract data from your database seems pretty simple and direct. SQL Server makes it easypie and Oracle seems to think it's funny to make me jump through hoops.
--matt
stop the stupid!
Catching up...
I'll have a few types of posts here for your reading pleasure.
Stupids - how other members of development or IT hurt my brains
Kodars - how code can hurt the database server
Code snippets - fun and helpful SQL (or pl sql) based code to help you
SQL vs Oracle - ok ok there is probably a place for them both in the world, but there are some things that just drive me insane. Sharing the pain and finding the appropriate solutions to every day problems.
Fun stuff - movie, book, tv and other reviews that will keep us from spending too much time on technology.
-- matt
Fight the stupid!
