Please start any new threads on our new
site at https://forums.sqlteam.com. We've got lots of great SQL Server
experts to answer whatever question you can come up with.
| Author |
Topic |
|
programmer76
Starting Member
6 Posts |
Posted - 2006-06-01 : 21:56:35
|
| Hi,I've started working on this new project. I've a big query below that is joining around 20 table. Developer before me had written it and i've to correct it.How can i make possible improvement in this query? If i remove some tables or some AND conditions from query then i got thousands of records. I've already created good indexes on all the tables in query. There are no table scans in the execution plan. There are NO book marks. There are some Index scans in the plan but can't take care of that because there are more than 20 tables i'm trying to join here.I will really appreciate your feedback.ThanksSELECT DISTINCT Orders.Order_ID, Orders.Order_DateOrdered, Orders.Order_Taxes, Orders.Order_Commission, Orders.Order_Comments, Orders.Order_OrderNumber, Orders.Order_CustomerNumber, Orders.Order_Supplier, Orders.Order_CCUsed, Orders.Order_OrderedBy , Orders.Order_Shipping,Orders.Order_AddressInfo,Orders.Order_FullAddressInfo,GiftPurchase.GiftPurchase_Quantity, GiftPurchase.GiftPurchase_Price, GiftPurchase.GiftPurchase_Shipping, GiftPurchase.GiftPurchase_Taxes, UserProduct.UserProduct_Name, UserProduct.UserProduct_Description,UserProduct.UserProduct_ModelType, UserProduct.UserProduct_DeliveryOption, UserProduct.UserProduct_ID, Shipping.Shipping_ShippedBy, Shipping.Shipping_DateShipped, Shipping.Shipping_ShipmentArrivalDate, Shipping.Shipping_Tracking, Shipping_TransactionFee, Shipping.Shipping_ShipmentMethod, Shipping.Shipping_Cost, Request.Request_Event, ShippingCollection_TS, ShippingCollection_ID,ShippingCollection_MerchantOrderNumber, ShippingCollection_OrderNumber, SupplierOrder_OrderNumber , SupplierOrder_ID, Store_ID,Person_ID, Person_Forename, Person_Surname, Person_Email FROM Orders, GiftPurchase, UserProduct, SupplierOrderOrders, SupplierOrder, Shipping, Request, ShippingCollection, Store, Supplier,Reqfill, Transactions, Person, Event , Purchaser , GiftSupplierFilled, AllocatedGift, AllocateGiftToSupplier WHERE GiftPurchase.GiftPurchase_Request = UserProduct.UserProduct_Request AND Request.Request_ID = UserProduct.UserProduct_Request AND Orders.Order_ID= GiftPurchase.GiftPurchase_Order AND SupplierOrderOrders.SupplierOrderOrders_Orders = Orders.Order_IDAND SupplierOrderOrders.SupplierOrderOrders_SupplierOrder = SupplierOrder.SupplierOrder_IDAND SupplierOrder.SupplierOrder_Supplier = Supplier_IDAND GiftPurchase.GiftPurchase_Shipping = Shipping.Shipping_ID AND ShippingCollection.ShippingCollection_Shipping = Shipping.Shipping_IDAND Supplier_ID = 703 AND Supplier_Store = Store_IDAND Request_ID = Reqfill_RequestAND Request_Event = Event_IDAND Purchaser_Person = Person_IDAND Purchaser_Transaction = Transaction_ID AND Reqfill_Transaction = Transaction_ID AND Orders.Order_ID = GiftSupplierFilled.GiftSupplierFilled_OrderAND UserProduct.UserProduct_ID=GiftSupplierFilled.GiftSupplierFilled_UserProduct AND UserProduct.UserProduct_ID = AllocatedGift.AllocatedGift_UserProduct AND Transactions.Transaction_ID = AllocatedGift.AllocatedGift_TransactionAND AllocatedGift.AllocatedGift_ID = AllocateGiftToSupplier.AllocateGiftToSupplier_AllocatedGift AND GiftSupplierFilled.GiftSupplierFilled_AllocateGiftToSupplier = AllocateGiftToSupplier.AllocateGiftToSupplier_IDAND Person_Surname like '%Takaba%' ORDER BY ShippingCollection_ID DESC, Request_Event, SupplierOrder_ID, Orders.Order_ID, UserProduct.UserProduct_ID; |
|
|
khtan
In (Som, Ni, Yak)
17689 Posts |
Posted - 2006-06-01 : 22:07:28
|
Try - rewriting the query using proper JOIN syntax ? - prefix the tables with owner ?SELECT ...FROM dbo.Orders o INNER JOIN dbo.GiftPurchase g ON o.Order_ID= g.GiftPurchase_Order INNER JOIN dbo.UserProduct. . . KH |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2006-06-02 : 03:18:47
|
| You can make a tremendous improvement for this query! As it is right now, you are selecting the cartesian product (all possible combinations) for the 18 tables you have. That would easily bring the query optimizer to it's knees. Multiply the number of records in every 18 tables you have and post the number here. I'll bet the product is some billions and more. I'll write down some things for you to do now. Remember to use fully qualified named (Order.OrderID, not just OrderID) in the future, for your own sake. It will be much easier to debug sometime in the future. If succeeding to implement the things written below, I would estimate that this query would perform at least 100 times better.1. Rewrite for using INNER JOINs SELECT Orders.Order_ID ... FROM Orders INNER JOIN GiftPurchase ON GiftPurchase.GiftPurchase_Order = Orders.Order_ID INNER JOIN ...I tried to do that for you, but since there are many unqualified names, it wasn't possible for me, since I can't see the table layouts.2. Place everything in a VIEW, except AND Supplier_ID = 703 AND Person_Surname like '%Takaba%'Then call the view from your stored procedure as SELECT * FROM MyView WHERE MyView.Supplier_ID = 703 AND MyView.Person_Surname LIKE '%Takaba%'This way, the query optimizer in SQL Server doesn't have to recompile the joins every time! Also, if searching for surname "Takaba", do not use LIKE with % first! That triggers a table scan. If searching for just "Takaba", write Person_surname = 'Takaba'3. If possible, make the view indexed. That's my opninion. |
 |
|
|
Maux Maux
Starting Member
10 Posts |
Posted - 2006-06-02 : 14:44:45
|
Ever so slight nitpick on rewriting 1. Rewrite for using INNER JOINsSELECT Orders.Order_ID...FROM Orders OINNER JOIN GiftPurchase GP ON GP.GiftPurchase_Order = O.Order_IDINNER JOIN ... |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2006-06-02 : 15:09:44
|
quote: Originally posted by Maux Maux Ever so slight nitpick on rewriting 1. Rewrite for using INNER JOINsSELECT Orders.Order_ID...FROM Orders OINNER JOIN GiftPurchase GP ON GP.GiftPurchase_Order = O.Order_IDINNER JOIN ...
Well, sometimes my mind is faster than my fingers |
 |
|
|
nr
SQLTeam MVY
12543 Posts |
Posted - 2006-06-03 : 11:59:58
|
quote: Originally posted by Peso [size=2][font=Verdana]You can make a tremendous improvement for this query! As it is right now, you are selecting the cartesian product (all possible combinations) for the 18 tables you have. That would easily bring the query optimizer to it's knees. Multiply the number of records in every 18 tables you have and post the number here. I'll bet the product is some billions and more.
It's not a cartesian product. The tables are joined in the where clause.Changing to ansi join syntax shouldn't make any difference to the query plan or result.Also placing the joins in a view shouldn't make any difference.Indexing the view would probably help performance at the expense of space.==========================================Cursors are useful if you don't know sql.DTS can be used in a similar way.Beer is not cold and it isn't fizzy. |
 |
|
|
LoztInSpace
Aged Yak Warrior
940 Posts |
Posted - 2006-06-04 : 21:00:32
|
| Well said nr.prog 76 - It seems to me you need to tell us what's wrong with the query. Is it slow? Are you getting different rows than what you expect? Are you simply freaked out by the fact it uses 20 tables? (Sometimes you cannont answer the question you are asking without using a lot of tables - live with it).It looks like you've got conditions on plenty of PKs (store_id, event_id etc) so I'd be surprised if performance is too bad.That fact you tried to randomly remove tables and conditions and have not stated what exactly is "wrong" with the query says to me you don't really understand the problem you are trying to solve. That might be a good place to start. |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2006-06-05 : 17:14:46
|
Nothing beats a real world example.I don't think the two syntaxes makes the query optimizer work the same way. The two types of syntaxes behave like the same, of course, but the query optimizer works in a little different way.I have come up with a very simple test-script to prove my point with the difference of INNER JOIN (ANSI SQL-92) syntax and "Cartesian product With Where" (ANSI SQL-86) syntax. First of all, my Members table has only 2,429 records and Models table has only 11,247 records, so the cartesian product is small; 27,318,963 records only.I created a table named Table1 which has three fields.1. z INT IDENTITY(1, 1)2. cart INT (for cartesian times)3. injo INT (for inner join times)The script itself is very simple.
declare @s datetime, @i smallint, @dummy int, @a int, @b int, @e intselect @e = 100while @e > 0begin select @i = 100, @s = getdate() while @i > 0 SELECT @dummy = count(*), @i = @i - 1 FROM models CROSS JOIN members WHERE members.memberid = models.memberid select @a = datediff(ms, @s, getdate()) select @i = 100, @s = getdate() while @i > 0 SELECT @dummy = count(*), @i = @i - 1 FROM models INNER JOIN members on members.memberid = models.memberid select @b = datediff(ms, @s, getdate()) insert table1 (cart, injo) values (@a, @b) select @e = @e - 1end to get the result, i just write select sum(cart) 'cartesian product ms', sum(injo) 'inner join ms' from table1 On my laptop, the results areCartesian product ms Inner join ms54057 53058 a difference of nearly 2 percent! And this is for only one join on two small sets. It is also noteable that both queries uses the same query plan! I urge other people to run the this test on their tables, preferrably 18 joins and millions of records in each table. Please post your results here...Here is also my complete list of times.
z cart injo ----------- ----------- ----------- 1 670 5162 530 5303 533 5304 546 5305 533 5306 543 5337 533 5308 533 5309 533 53010 530 53011 546 53312 546 54313 533 53014 546 51615 546 53016 533 53017 533 53018 533 53019 546 53020 533 53021 530 53022 533 53023 530 53024 546 51625 530 53026 533 53027 533 53028 533 53329 546 53030 533 53031 533 53032 533 53033 546 53034 546 53335 546 51336 533 53037 533 53038 533 53039 533 53040 546 53041 546 53342 530 53043 533 53044 533 53045 533 53046 533 53047 546 53048 533 53049 543 53350 533 53051 533 53052 546 51653 530 53054 546 53355 546 53056 533 53057 533 53058 533 53059 533 53060 533 53061 533 53062 530 53063 546 53364 533 53065 533 53066 546 53067 546 53068 546 53369 530 53070 546 53371 533 53072 533 53073 530 53074 533 53075 546 53376 533 53077 563 54678 546 53079 576 55080 546 53081 576 53382 546 54683 533 53084 550 54385 563 53086 546 54687 546 51688 546 53089 546 53090 550 54691 546 54392 546 53093 533 53094 530 53095 546 51396 546 53397 530 53098 550 53099 530 530100 533 530(100 row(s) affected) |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2006-06-05 : 17:54:42
|
quote: Nothing beats a real world example....On my laptop, the results areCartesian product ms Inner join ms54057 53058
Putting the two types of queries into views, produces following timescartesian product ms inner join ms -------------------- ------------- 54093 52740 This is now over 2 percent faster but also faster than not using views, a total of 2.5 percent faster than the original posting...Here we also can note that putting ANSI SQL-86 syntax in a view did not gain performance at all.Conclusion:Using ANSI SQL-92 with views is over 2.5 percent faster than using ANSI SQL-86 inline, with small sets of data. The performance with large sets of data and multiple joins, is up to everyone here to figure out. |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2006-06-05 : 18:02:48
|
quote: Originally posted by nr
Originally posted by Peso You can make a tremendous improvement for this query! As it is right now, you are selecting the cartesian product (all possible combinations) for the 18 tables you have. That would easily bring the query optimizer to it's knees. Multiply the number of records in every 18 tables you have and post the number here. I'll bet the product is some billions and more. It's not a cartesian product.Yes, it is.The tables are joined in the where clause.Yes, sort of.Changing to ansi join syntax shouldn't make any difference to the query plan or result.Well, it did made a difference in speed.Also placing the joins in a view shouldn't make any difference.Well, it did made a difference in speed.Indexing the view would probably help performance at the expense of space.Is that a problem?
I just posted my opinions, based on my experience with SQL Server, to help programmer76 out a little. I thought my posting were helpful. And with my, test-script, I proved my point.How were you helpful? |
 |
|
|
LoztInSpace
Aged Yak Warrior
940 Posts |
Posted - 2006-06-05 : 21:19:04
|
| Hi Peso,I notice the faster wall-clock time is lower on the second case each time. However, you say the query plans are the same. I therefore put it to you that the performance difference you see is more related to the earlier query putting the data pages in the cache than the (identically planned) execution being more efficient. Can you try:1) Running them in the different order2) Running the same query twice (or more) times in a rowand post the results?Personally I don't really like measuring performance by the elapsed time. There are too many variables especially when you add multiple users to the mix. I think the key is to get an efficient execution plan - all the rest is envrionmental. I'm happy to be proven wrong though. |
 |
|
|
SwePeso
Patron Saint of Lost Yaks
30421 Posts |
Posted - 2006-06-06 : 05:37:59
|
Changing the order of ANSI SQL-86 and ANSI SQL-92 queries produced following timescartesian product ms inner join ms -------------------- ------------- 53153 51727 and this is a time difference of nearly 3 percent. But these times were made after a clean restart of SQL Server and computer, and the times posted last night was produced after a full day work. I stick with the times produced last night, since those queries were made near a real production environment, not a clean startup.Having two ANSI SQL-92 queries in the @e-loop produced following time104932 ms and having two ANSI SQL-86 in th @e-loop produced following time106409 ms Now 1.5 percent difference. I'll say that is within the marginal error compared with earlier results. |
 |
|
|
|
|
|
|
|