1: | When could a stored procedure cause serious performance problems? |
A1: | Stored procedures can cause problems when a stored optimization plan is unsuitable for the current set of parameters. |
2: | Can you give an example of the previous answer? |
A2: | Certain parameter sets will call for the use of an index, and others are better suited to a table scan. Use of the wrong optimization plan will cause a significant performance problem. You should use the RECOMPILE option. A typical example is a search based on a date range as shown.
Create procedure sp_datename (@startdate Datetime, @enddate Datetime) As Select * From tablename Where date Between @startdate and @enddate |
1: | The following procedure seems to take a long time to process. Can you identify the reason and correct it?
Create Procedure Sales_by_State (@start_date datetime, @end_date datetime) As Select od.productid, od.quantity, od.unitprice, ord.customerid into #tp_Sales From orders as ORD inner join [Order Details] as OD on ord.orderid = od.ordered Where ORD.orderdate between @start_date and @end_date Select cst.region, sum(tp.quantity * tp.unitprice) From Customers as cst left outer join #tp_sales as tp on cst.customerid = tp.customerid Group by tp.region |
A1: | As you have seen in this lesson, the reason this procedure is performing poorly is because the optimization of the procedure must guess at how large the temporary table will be. To fix this procedure, you need to break it up into two steps. First, you create two procedures; the first inner procedure will retrieve data from the temporary table, and the outer procedure will call the inner one to perform the complete process. The following SQL batch is an example of how this can be done:
Select od.productid, od.quantity, od.unitprice, ord.customerid Into #tp_Sales From orders as ORD inner join [Order Details] as OD on ord.orderid = od.ordered Go Create Procedure Sub_Sales_by_State With Recompile As Select cst.region, sum(tp.quantity * tp.unitprice) From Customers as cst left outer join #tp_sales as tp on cst.customerid = tp.customerid Group by tp.region Go Drop Table #tp_sales Go Create Procedure SP_Sales_by_State (@start_date datetime, @end_date datetime) As Select od.productid, od.quantity, od.unitprice, ord.customerid Into #tp_Sales From orders as ORD inner join [Order Details] as OD on ord.orderid = od.ordered Where ORD.orderdate between @start_date and @end_date Execute Sub_Sales_by_State Go |
2: | Create a procedure that updates the price of a product, passing the price and its product ID. This update must verify that the product is available (quantity >0) and the new price is greater than $12.00. If the update fails for any reason, return an error. Make sure to use transaction processing. |
A2: | There are many ways to work with transactions within a procedure. Using the methods discussed in this lesson, the following is an example of one way to use transactions:
Create Procedure sp_Update_products (@prodID int, @price Money) As Declare @err int, @rowcount int If @price <= $12 Begin Raiserror ('Price entered must be greater than $12 dollars', 16,1) Return 99 End Begin Transaction Save Transaction sp_update_products Update products Set unitprice = @price Where productid = @prodID Select @err = @@error Select @rowcount = @@rowcount If @err <> 0 Begin Rollback Transaction sp_update_products Commit Transaction Return 98 End If @rowcount = 0 Begin Print 'Product ID does not exist, exiting procedure' Commit Transaction Return 97 End If Isnull((Select UnitsInStock From Products Where productid = @prodID), 0) <= 0 Begin Raiserror ('Product is no longer available', 16, 1) Rollback Transaction sp_update_products Commit Transaction Return 96 End Commit Transaction Return 0 To test this procedure, you can use the following batch: Declare @ret_code int Execute @ret_code = sp_update_products 146, $15 If @ret_code <> 0 Begin Raiserror ('Return Code is %d', 0, 1, @ret_code) Return End Product is no longer available Return Code is 96 |
3: | Extra Credit: Create a system procedure that displays the usernames and login names of everyone using the current database. |
A3: | The usernames are in the system table Sysusers and the login names are in the Master..Sysusers table. (Hint: to create a system stored procedure, you must log in to the Master database as the system administrator SA, using the assigned password.)
Create Procedure sp_Users_New As Select users.name, login.name From sysusers as users Inner Join Master..sysusers as login on users.uid = login.uid |