views:

230

answers:

5

I had a heated discussion with a colleague on the usage of stored procedures (SP) in a .NET application (on an SQL server 2005 database). [He has a Microsoft background and I Java - which may or may not be relevant].

I have to insert data captured in the UI. For this I would write a SP and use that in the .NET code? It's not required but what are the pros and cons of using a SP?

Another scenario:

I am maintaining a list of cities. User can add cities using the UI. As you expect user cannot enter a duplicate city. An error will be shown if duplicate entry happens. this can be implemented in a number of ways:

  1. In my code run a select query to check if it already exists and then if not insert the city otherwise an error on UI.
  2. Insert directly and due to unique index an SQLException will be caught. Introspect the SQLException to check what unique index is violated and show the respective error.
  3. create one SP and in that handle the above logic, i.e. checking for duplicate and throw error or insert

Which one is the right way? (links to good resources are welcome).

+2  A: 

If you are intending to write one sp that will do all the checking and insert if it is able to, then why not return the number of rows modified and if it is greater than zero, your method was succesful. I would avoid having an exception, the idea is that not being able to insert is not really exceptional, just undesireable. Your insert method caling the stored proc can read an output parameter and tell it's caller if it inserted anything.

Mark Dickinson
+6  A: 

Firstly, it is a good idea to use SPs, rather than adhoc SQL statements because: 1) security - only need to grant permission to execute the sproc, NOT on the underlying tables 2) maintainability - can patch the SP within SQL Server without having to rebuild/deploy .NET code in order to tweak a query 3) performance - execution plan caching/reuse when using sprocs improves performance (can be done also if using parameterised SQL direct within your .NET) 4) network traffic (ok, negligible but SPs save you passing the whole SQL statement across the network, particularly if large query)

Exceptions are expensive, so try to avoid exceptions being thrown when you can prevent it. I'd recommend writing a sproc that does an IF EXISTS check prior to trying to INSERT a record and only inserting if it doesn't exist. Just return out a return code or output parameter indicating what happened. e.g. 0=inserted OK, -1=already exists

Do it all within the one sproc call to save DB round trips (i.e. don't query the db first to check, and then send another statement in to do the INSERT). Using an EXISTS check is the most optimal way of checking.

AdaTheDev
Your point number 3 is not quite right, any sql statement you run, either written in the .net code, or using an sp, will be cached and optimised the next time it is run, sps are no different to raw sql in this regard. It is the parameterisation that gives you the security and reduces the size of the call going out.
Mark Dickinson
If you send in "SELECT * FROM MyTable WHERE Field='A'" and then send in "SELECT * FROM MyTable WHERE Field='B'" then you end up with 2 separate execution plans in the cache, not 1. It's only if you send in the exact same adhoc raw SQL min this case that it will reuse the execution plan - hence parameterisation is key e.g. SELECT * FROM MyTable WHER Field=@Value, which will perform as well as a sproc as whatever value you assign to @Value, will result in the SAME execution plan getting used.
AdaTheDev
If you are writing adhoc Queries then they will be cached for the EXACT query like AdaTheDev says. This is why using sprocs is better because the entire thing is cached and the values can easily be changed.
AutomatedTester
1) is relevant if you have multiple applications sharing a database. I wouldn't use that model as I tend work in an latency sensitive, event driven environment. 2) is useful if you have a rapid prototyping style of project and you are willing to accept a high level of risk in production and you don't expect that to change 3) depending on your data size, it may be faster to cache your data in memory. If your data requirement is too large use a specialised database 4) This can be very true, but I would optimise only the queries I know to be an issue rather than assume I need to optimise them all
Peter Lawrey
2) is also useful where you have a multi-client (multi-db instance) product where you have very different data quantities/usage patterns etc between them. A one size fits all query in this environment can often cause much pain and in certain circumstances, slightly different versions of the query provide better performance when tailored specifically. Ability to simply deploy custom versions of certain SPs is invaluable. It does require a robust build and deployment process, which is key.
AdaTheDev
What is the problem in granting access directly to tables? Most of the database changes will surely affect the .Net code, rarely the change can be managed by change in SP only. Thirds point is irrelevant, isn't it? Negligible time in transferring the SQL statement to DB at the cost of complication, breaking layered architecture, loosing flexibility of introducing clustered caching layer.
Bhushan
1) Granting access directly tables is never going to be *more* secure than just to sprocs.2) If you have a critical bug because your query is performing badly or worse, just returning wrong data and it needs fixing ASAP it's not ideal to have to rebuild/redeploy the whole solution when you can just patch the sproc.3) Performance is far from irrelevant. As I said before, both SPs and SQL constructed within .NET code can perform equally well as long as parameterised SQL is used within .NET code. Easier to tune the DB when things are in SPs IMHO.4) I did say it was negligible :)
AdaTheDev
+6  A: 

As a general rule of thumb, if the application is the only user of a given database schema, then I would advise using direct SQL (i.e. no SPs). If the database is shared between applications, it becomes much more critical to control the interface between applications and shared data, and the easiest way to define this interface is to control access to the data via stored procedures.

The use of SPs adds to the complexity of the system, and you shouldn't add complexity unless there's a good reason for it. It can also severely hamper your application's use of good ORM tools.

But as with all rules of thumb, there are always exceptions.

skaffman
If you use stored procedures and the underlying structure changes, you might have to change things on +1 site. SPs are good for batch-like processing when the data does not need to leave the DB. Also if your db is accessed by 3rd party, it might be safer to hand them an SP and a few import/export tables.
kd304
Absolutely, never give 3rd parties direct access to the tables. For that matter, I'd think twice about giving them access to the database at all, and give them a web service instead.
skaffman
I agree with skaffman, 3rd party should use a webservice to interact with your data.
Bhushan
+4  A: 

I like the idea of separating the data tier and the business logic tier. Therefore I am not putting any business logic to database but in code in my domain.

If you are using some kind of ORM like NHibernate, the role of the database will automatically become just a storage and nothing else. You need to be careful when you start implementing parts of the business logic on the database and another part in your application!

Best Regards

Oliver Hanappi
I am not using any ORM but I still don't like the idea of SPs simple to interact with tables. SPs are there for doing larger tasks in database.
Bhushan
+1  A: 

I don't think there is a one size solution. If you want common code between a Java and a.NET solution, then SP in SQL may be the best choice.

In the past I have avoided using any stored procedures as it make deployment in a controlled environment more difficult. Sure you can update a procedure here or there in a simple way but in a large system this can be more of a curse than a blessing.

It depends on how much control over your environment you would like. e.g. I prefer to have confidence that UAT and production are the same. i.e. if it works in UAT it will work in production.

If there is just the two of you, then it probably doesn't matter, you will be able to easily fix any inconsistencies between environments (assuming you have multiple environments)

However for a more complex system with more environments, multiple regions, developers in different time zones you will want the deployment and roll back of a new system as simple as possible. For a Java deployment, it just a matter of changing a symbolic link and restarting the service.

It is also fairly easy to have two versions of the software running at once so you can do last minute tests, change over and change back your production environment easily during the day rather than wait for down time. Perhaps there is a simple way to do this in SQL, but I haven't come across one.

In summary: agree on your requirements for the whole end-to-end process first and then find solutions to match, too often people start with solutions they are comfortable with, focus on one aspect to justify their choice. They often discover very late in the project a requirement which is a major headache which is too late to change, but it would have been simple if it had been considered from the start.

Peter Lawrey
I agree with you Pater but people think deploying multiple instances of an app is cumbersome then changing SP in one db instance. Instead I thought db changes are always riskier then any other change. Also most of the times the changes cannot be hidden by change in SP only.
Bhushan
Deploying multiple instances of an app is more cumbersome than SP changes. If you have a bug in your query logic then making a change in one place and having a relatively small downtime window would always win over having to take down an entire farm and redeploying it. If your app handles SQLExceptions properly then your farm can still take requests and use them later(assuming you have coded retry methods) rather than just showing a 404 or 500 error
AutomatedTester