SQL Statement running extreamly Slow - sql-server-2008
Okay I have look through several posts about SQL running slow and I didn't see anything similar to this, so my apologies if I missed one. I was asked about a month ago to create a view that would allow the user to report what hasn't been billed yet, and the SQL is joining 4 tables together. One is 1.2 million records ish. the rest are between 80K - 250K. (Please note that this should only return around 100 records after the where statements).
SELECT C.Cltnum + '.' + C.CltEng AS [ClientNum],
C.CPPLname,
w.WSCDesc,
MIN(w.Wdate) AS [FirstTDate],
w.WCodeCat,
w.WCodeSub,
SUM(w.Wbilled) AS [Billed],
SUM(w.Whours * w.Wrate) AS [Billable Wip],
sum(ar.[ARProgress]) AS [Progress],
w.Winvnum,
-- dbo.GetInvoiceAmount(w.Winvnum) AS [InvoiceAmount],
SUM(cb.cinvar) AS [AR Balance]
FROM dbo.WIP AS w
--Never join on a select statement
--join BillingAuditCatagoriesT bac on w.WCodeCat = bac.Catagory and w.WCodeSub = bac.Subcatagory
INNER JOIN dbo.Clients AS C ON w.WCltID = C.ID
JOIN dbo.ClientBuckets AS cb on c.cltnum = cb.cltnum
JOIN dbo.AcctsRec AS ar on ar.arapplyto = w.[Winvnum]
-- WHERE w.wcodecat = '1AUDT'
GROUP BY C.Cltnum, C.CltEng, C.CPPLname, w.WCodeCat, w.Wdate, w.Winvnum, w.WCodeSub, w.WSCDesc
so, where I think there may be a problem is that Category is a varchar it is xat, ACT, BID and there are about 15 different Category. this is the same as SubCat. you will notice that there are 3 functions on this and they are GetJamesProgress Which is = (SELECT sum(Amount) From Progress Where inv = w.invnum) and the same with GetInvoiceAmount and GetJamesARBalance. I know that this is bad to do but when I join by invoice number it takes even longer than with out them.
Please help thanks so much!
Related
Optimizing Parameterized MySQL Queries
I have a query that has a number of parameters which if I run from in MySQLWorkbench takes around a second to run. If I take this query and get rid of the parameters and instead substitute the values into the query then it takes about 22 seconds to run, same as If I convert this query to a parameterized stored procedure and run it (it then takes about 22 seconds). I've enabled profiling on MySQL and I can see a few things there. For example, it shows the number of rows examined and there's an order of difference (20,000 to 400,000) which I assume is the reason for the 20x increase in processing time. The other difference in the profile is that the parameterized query sent from MySQLWorkbench still has the parameters in (e.g. where limit < #lim) while the sproc the values have been set (where limit < 300). I've tried this a number of different ways, I'm using JetBrains's DataGrip (as well as MySQLWorkbench) and that works like MySQLWorkbench (sends through the # parameters), I've tried executing the queries and the sproc from MySQLWorkbench, DataGrip, Java (JDBC) and .Net. I've also tried prepared statements in Java but I can't get anywhere near the performance of sending the 'raw' SQL to MySQL. I feel like I'm missing something obvious here but I don't know what it is. The query is relatively complex, it has a CTE a couple of sub-selects and a couple of joins, but as I said it runs quickly straight from MySQL. My main question is why the query is 20x faster in one format than another. Does the way the query is sent to MySQL have anything to do with this (the '#' values sent through and can I replicate this in a stored procedure? Updated 1st Jan Thanks for the comments, I didn't post the query originally as I'm more interested in the general concepts around the use of variables/parameters and how I could take advantage of that (or not) Here is the original query: with tmp_bat as (select bd.MatchId, bd.matchtype, bd.playerid, bd.teamid, bd.opponentsid, bd.inningsnumber, bd.dismissal, bd.dismissaltype, bd.bowlerid, bd.fielderid, bd.score, bd.position, bd.notout, bd.balls, bd.minutes, bd.fours, bd.sixes, bd.hundred, bd.fifty, bd.duck, bd.captain, bd.wicketkeeper, m.hometeamid, m.awayteamid, m.matchdesignator, m.matchtitle, m.location, m.tossteamid, m.resultstring, m.whowonid, m.howmuch, m.victorytype, m.duration, m.ballsperover, m.daynight, m.LocationId from (select * from battingdetails where matchid in (select id from matches where id in (select matchid from battingdetails) and matchtype = #match_type )) as bd join matches m on m.id = bd.matchid join extramatchdetails emd1 on emd1.MatchId = m.Id and emd1.TeamId = bd.TeamId join extramatchdetails emd2 on emd2.MatchId = m.Id and emd2.TeamId = bd.TeamId ) select players.fullname name, teams.teams team, '' opponents, players.sortnamepart, innings.matches, innings.innings, innings.notouts, innings.runs, HS.score highestscore, HS.NotOut, CAST(TRUNCATE(innings.runs / (CAST((Innings.Innings - innings.notOuts) AS DECIMAL)), 2) AS DECIMAL(7, 2)) 'Avg', innings.hundreds, innings.fifties, innings.ducks, innings.fours, innings.sixes, innings.balls, CONCAT(grounds.CountryName, ' - ', grounds.KnownAs) Ground, '' Year, '' CountryName from (select count(case when inningsnumber = 1 then 1 end) matches, count(case when dismissaltype != 11 and dismissaltype != 14 then 1 end) innings, LocationId, playerid, MatchType, SUM(score) runs, SUM(notout) notouts, SUM(hundred) Hundreds, SUM(fifty) Fifties, SUM(duck) Ducks, SUM(fours) Fours, SUM(sixes) Sixes, SUM(balls) Balls from tmp_bat group by MatchType, playerid, LocationId) as innings JOIN players ON players.id = innings.playerid join grounds on Grounds.GroundId = LocationId and grounds.MatchType = innings.MatchType join (select pt.playerid, t.matchtype, GROUP_CONCAT(t.name SEPARATOR ', ') as teams from playersteams pt join teams t on pt.teamid = t.id group by pt.playerid, t.matchtype) as teams on teams.playerid = innings.playerid and teams.matchtype = innings.MatchType JOIN (SELECT playerid, LocationId, MAX(Score) Score, MAX(NotOut) NotOut FROM (SELECT battingdetails.playerid, battingdetails.score, battingdetails.notout, battingdetails.LocationId FROM tmp_bat as battingdetails JOIN (SELECT battingdetails.playerid, battingdetails.LocationId, MAX(battingdetails.Score) AS score FROM tmp_bat as battingdetails GROUP BY battingdetails.playerid, battingdetails.LocationId, battingdetails.playerid) AS maxscore ON battingdetails.score = maxscore.score AND battingdetails.playerid = maxscore.playerid AND battingdetails.LocationId = maxscore.LocationId ) AS internal GROUP BY internal.playerid, internal.LocationId) AS HS ON HS.playerid = innings.playerid and hs.LocationId = innings.LocationId where innings.runs >= #runs_limit order by runs desc, KnownAs, SortNamePart limit 0, 300; Wherever you see '#match_type' then I substitute that for a value ('t'). This query takes ~1.1 secs to run. The query with the hard coded values rather than the variables down to ~3.5 secs (see the other note below). The EXPLAIN for this query gives this: 1,PRIMARY,<derived7>,,ALL,,,,,219291,100,Using temporary; Using filesort 1,PRIMARY,players,,eq_ref,PRIMARY,PRIMARY,4,teams.playerid,1,100, 1,PRIMARY,<derived2>,,ref,<auto_key3>,<auto_key3>,26,"teams.playerid,teams.matchtype",11,100,Using where 1,PRIMARY,grounds,,ref,GroundId,GroundId,4,innings.LocationId,1,10,Using where 1,PRIMARY,<derived8>,,ref,<auto_key0>,<auto_key0>,8,"teams.playerid,innings.LocationId",169,100, 8,DERIVED,<derived3>,,ALL,,,,,349893,100,Using temporary 8,DERIVED,<derived14>,,ref,<auto_key0>,<auto_key0>,13,"battingdetails.PlayerId,battingdetails.LocationId,battingdetails.Score",10,100,Using index 14,DERIVED,<derived3>,,ALL,,,,,349893,100,Using temporary 7,DERIVED,t,,ALL,PRIMARY,,,,3323,100,Using temporary; Using filesort 7,DERIVED,pt,,ref,TeamId,TeamId,4,t.Id,65,100, 2,DERIVED,<derived3>,,ALL,,,,,349893,100,Using temporary 3,DERIVED,matches,,ALL,PRIMARY,,,,114162,10,Using where 3,DERIVED,m,,eq_ref,PRIMARY,PRIMARY,4,matches.Id,1,100, 3,DERIVED,emd1,,ref,"PRIMARY,TeamId",PRIMARY,4,matches.Id,1,100,Using index 3,DERIVED,emd2,,eq_ref,"PRIMARY,TeamId",PRIMARY,8,"matches.Id,emd1.TeamId",1,100,Using index 3,DERIVED,battingdetails,,ref,"TeamId,MatchId,match_team",match_team,8,"emd1.TeamId,matches.Id",15,100, 3,DERIVED,battingdetails,,ref,MatchId,MatchId,4,matches.Id,31,100,Using index; FirstMatch(battingdetails) and the EXPLAIN for the query with the hardcoded values looks like this: 1,PRIMARY,<derived8>,,ALL,,,,,20097,100,Using temporary; Using filesort 1,PRIMARY,players,,eq_ref,PRIMARY,PRIMARY,4,HS.PlayerId,1,100, 1,PRIMARY,grounds,,ref,GroundId,GroundId,4,HS.LocationId,1,100,Using where 1,PRIMARY,<derived2>,,ref,<auto_key0>,<auto_key0>,30,"HS.LocationId,HS.PlayerId,grounds.MatchType",17,100,Using where 1,PRIMARY,<derived7>,,ref,<auto_key0>,<auto_key0>,46,"HS.PlayerId,innings.MatchType",10,100,Using where 8,DERIVED,matches,,ALL,PRIMARY,,,,114162,10,Using where; Using temporary 8,DERIVED,m,,eq_ref,"PRIMARY,LocationId",PRIMARY,4,matches.Id,1,100, 8,DERIVED,emd1,,ref,"PRIMARY,TeamId",PRIMARY,4,matches.Id,1,100,Using index 8,DERIVED,emd2,,eq_ref,"PRIMARY,TeamId",PRIMARY,8,"matches.Id,emd1.TeamId",1,100,Using index 8,DERIVED,<derived14>,,ref,<auto_key2>,<auto_key2>,4,m.LocationId,17,100, 8,DERIVED,battingdetails,,ref,"PlayerId,TeamId,Score,MatchId,match_team",MatchId,8,"matches.Id,maxscore.PlayerId",1,3.56,Using where 8,DERIVED,battingdetails,,ref,MatchId,MatchId,4,matches.Id,31,100,Using index; FirstMatch(battingdetails) 14,DERIVED,matches,,ALL,PRIMARY,,,,114162,10,Using where; Using temporary 14,DERIVED,m,,eq_ref,PRIMARY,PRIMARY,4,matches.Id,1,100, 14,DERIVED,emd1,,ref,"PRIMARY,TeamId",PRIMARY,4,matches.Id,1,100,Using index 14,DERIVED,emd2,,eq_ref,"PRIMARY,TeamId",PRIMARY,8,"matches.Id,emd1.TeamId",1,100,Using index 14,DERIVED,battingdetails,,ref,"TeamId,MatchId,match_team",match_team,8,"emd1.TeamId,matches.Id",15,100, 14,DERIVED,battingdetails,,ref,MatchId,MatchId,4,matches.Id,31,100,Using index; FirstMatch(battingdetails) 7,DERIVED,t,,ALL,PRIMARY,,,,3323,100,Using temporary; Using filesort 7,DERIVED,pt,,ref,TeamId,TeamId,4,t.Id,65,100, 2,DERIVED,matches,,ALL,PRIMARY,,,,114162,10,Using where; Using temporary 2,DERIVED,m,,eq_ref,PRIMARY,PRIMARY,4,matches.Id,1,100, 2,DERIVED,emd1,,ref,"PRIMARY,TeamId",PRIMARY,4,matches.Id,1,100,Using index 2,DERIVED,emd2,,eq_ref,"PRIMARY,TeamId",PRIMARY,8,"matches.Id,emd1.TeamId",1,100,Using index 2,DERIVED,battingdetails,,ref,"TeamId,MatchId,match_team",match_team,8,"emd1.TeamId,matches.Id",15,100, 2,DERIVED,battingdetails,,ref,MatchId,MatchId,4,matches.Id,31,100,Using index; FirstMatch(battingdetails) Pointers as to ways to improve my SQL are always welcome (I'm definitely not a database person), but I''d still like to understand whether I can use the SQL with the variables from code and why that improves the performance by so much Update 2 1st Jan AAArrrggghhh. My machine rebooted overnight and now the queries are generally running much quicker. It's still 1 sec vs 3 secs but the 20 times slowdown does seem to have disappeared
In your WITH construct, are you overthinking your select in ( select in ( select in ))) ... overstating what could just be simplified to the with Innings I have in my solution. Also, you were joining to the extraMatchDetails TWICE, but joined on the same conditions on match and team, but never utliized either of those tables in the "WITH CTE" rendering that component useless, doesn't it? However, the MATCH table has homeTeamID and AwayTeamID which is what I THINK your actual intent was Also, your WITH CTE is pulling many columns not needed or used in subsequent return such as Captain, WicketKeeper. So, I have restructured... pre-query the batting details once up front and summarized, then you should be able to join off that. Hopefully this MIGHT be a better fit, function and performance for your needs. with innings as ( select bd.matchId, bd.matchtype, bd.playerid, m.locationId, count(case when bd.inningsnumber = 1 then 1 end) matches, count(case when bd.dismissaltype in ( 11, 14 ) then 0 else 1 end) innings, SUM(bd.score) runs, SUM(bd.notout) notouts, SUM(bd.hundred) Hundreds, SUM(bd.fifty) Fifties, SUM(bd.duck) Ducks, SUM(bd.fours) Fours, SUM(bd.sixes) Sixes, SUM(bd.balls) Balls from battingDetails bd join Match m on bd.MatchID = m.MatchID where matchtype = #match_type group by bd.matchId, bd.matchType, bd.playerid, m.locationId ) select p.fullname playerFullName, p.sortnamepart, CONCAT(g.CountryName, ' - ', g.KnownAs) Ground, t.team, i.matches, i.innings, i.runs, i.notouts, i.hundreds, i.fifties, i.ducks, i.fours, i.sixes, i.balls, CAST( TRUNCATE( i.runs / (CAST((i.Innings - i.notOuts) AS DECIMAL)), 2) AS DECIMAL(7, 2)) 'Avg', hs.maxScore, hs.maxNotOut, '' opponents, '' Year, '' CountryName from innings i JOIN players p ON i.playerid = p.id join grounds g on i.locationId = g.GroundId and i.matchType = g.matchType join (select pt.playerid, t.matchtype, GROUP_CONCAT(t.name SEPARATOR ', ') team from playersteams pt join teams t on pt.teamid = t.id group by pt.playerid, t.matchtype) as t on i.playerid = t.playerid and i.MatchType = t.matchtype join ( select i2.playerid, i2.locationid, max( i2.score ) maxScore, max( i2.notOut ) maxNotOut from innings i2 group by i2.playerid, i2.LocationId ) HS on i.playerid = HS.playerid AND i.locationid = HS.locationid FROM where i.runs >= #runs_limit order by i.runs desc, g.KnownAs, p.SortNamePart limit 0, 300; Now, I know that you stated that after the server reboot, performance is better, but really, what you DO have appears to really have overbloated queries.
Not sure this is the correct answer but I thought I'd post this in case other people have the same issue. The issue seems to be the use of CTEs in a stored procedure. I have a query that creates a CTE and then uses that CTE 8 times. If I run this query using interpolated variables it takes about 0.8 sec, if I turn it into a stored procedure and use the stored procedure parameters then it takes about to a minute (between 45 and 63 seconds) to run! I've found a couple of ways of fixing this, one is to use multiple temporary tables (8 in this case) as MySQL cannot re-use a temp table in a query. This gets the query time right down but just doesn't fell like a maintainable or scalable solution. The other fix is to leave the variables in place and assign them from the stored procedure parameters, this also has no real performance issues. So my sproc looks like this: create procedure bowling_individual_career_records_by_year_for_team_vs_opponent(IN team_id INT, IN opponents_id INT) begin set #team_id = team_id; set #opponents_id = opponents_id; # use these variables in the SQL below ... end Not sure this is the best solution but it works for me and keeps the structure of the SQL the same as it was previously.
MYSQL Query - joining tables and grouping results
I'm after some help with a report I'm designing please. My report includes results from a booking database where I'd like to show each booking on a single line. However as the booking database has a number of tables my MYSQL query involves JOINS which is resulting in multiple rows per booking. It is the multiple results for "dcea4_eb_field_values.field_value" per booking causing the repeating rows. This is my query SELECT dcea4_eb_events.event_date, dcea4_eb_events.title, dcea4_eb_registrants.id, dcea4_eb_registrants.first_name, dcea4_eb_registrants.last_name, dcea4_eb_registrants.email, dcea4_eb_registrants.register_date, dcea4_eb_registrants.amount, dcea4_eb_registrants.comment, dcea4_eb_field_values.field_id, dcea4_eb_field_values.field_value FROM dcea4_eb_events INNER JOIN dcea4_eb_registrants ON dcea4_eb_registrants.event_id = dcea4_eb_events.id INNER JOIN dcea4_eb_field_values ON dcea4_eb_field_values.registrant_id = dcea4_eb_registrants.id WHERE 1=1 AND (dcea4_eb_field_values.field_id = 14 OR dcea4_eb_field_values.field_id = 26 OR dcea4_eb_field_values.field_id = 27 OR dcea4_eb_field_values.field_id = 15) AND dcea4_eb_registrants.published <> 2 AND dcea4_eb_registrants.published IS NOT NULL AND (dcea4_eb_registrants.published = 1 OR dcea4_eb_registrants.payment_method = "os_offline") [ AND (dcea4_eb_registrants.register_date {RegistrationDate} ) ] [ AND REPLACE(dcea4_eb_events.title,'\'','') in ({Club}) ] ORDER BY dcea4_eb_registrants.register_date, dcea4_eb_events.title This is what the output currently looks like current result and this is what I'd like it to look like desired result Any help appreciated
40 seconds strange sql performance puzzle
I'm running a query to update my user's field like the following: UPDATE Members SET abc = abc + 1 where Members.id in ( SELECT DISTINCT(memberId) FROM Events WHERE Events.createdAt > "2017-08-06 13:10:00"; Shockingly, with about 500 members, this query runs for 40 seconds... so the break down: SELECT DISTINCT(memberId) FROM Events WHERE Events.createdAt > "2017-08-06 13:10:00" runs for 0.1s and there're only 39 rows matched. The total # of Members is only ~500. I don't understand why this can take that long... Am I missing something? I'm running on RDS with mysql 5.6
Try replacing with exists: UPDATE Members m SET abc = abc + 1 WHERE EXISTS (SELECT 1 FROM events e WHERE e.memberId = m.id AND e.createdAt > '2017-08-06 13:10:00' ); For performance, you want an index on events(memberId, createdAt). My guess is that MySQL runs the subquery once for every row in Members. This is consistent with your timing -- ~0.1 seconds * ~500 rows is about 50 seconds, not that far off of 40 seconds. For SELECTs, this was fixed several versions ago. Perhaps this issue still exists in non-SELECT queries. You can also write this as: UPDATE Members m JOIN (SELECT DISTINCT e.memberId FROM events e WHERE e.createdAt > '2017-08-06 13:10:00' ) e ON e.memberId = m.id SET abc = abc + 1 ; Whether this is faster than the exists version, depends on characteristics of your data. Without the suggested index, this is likely to be faster.
SQL SUM issues with joins
I got a quite complex query (at least for me). I want to create a list of users that are ready to be paid. There are 2 conditions that need to be met: order status should be 3 and the total should be more then 50. Currently I got this query (generated with Codeingiter active record): SELECT `services_payments`.`consultant_id` , `consultant_userdata`.`iban` , `consultant_userdata`.`kvk`, `consultant_userdata`.`bic` , `consultant_userdata`.`bankname` , SUM(`services_payments`.`amount`) AS amount FROM (`services_payments`) JOIN `consultant_userdata` ON `consultant_userdata`.`user_id` = `services_payments`.`consultant_id` JOIN `services` ON `services`.`id` = `services_payments`.`service_id` WHERE `services`.`status` = 3 AND `services_payments`.`paid` = 0 HAVING `amount` > 50 The services_payments table contains the commissions, consultant_userdata contains the userdata and services keeps the order data. The current query only gives me 1 result while I'm expecting 4 results. Could someone please tell me what I'm doing wrong and what would be the solution?
For ActiveRecord, rsanchez' answer would be more of $this->db->group_by('services_payments.consultant_id, consultant_userdata.iban, consultant_userdata.kvk, consultant_userdata.bic, consultant_userdata.bankname');
Using MAX of a field to select a record returns MAX of the table ignores the condition
I'm doing a stored procedure for a report, and I'm trying to get only those records with the highest value of a determined field (accumulated amount), the thing is I can't seem to find the solution to this, the only solution that i've came up with is using an extra condition, the problem is the field changes every month (period) and not all the records are updated but I need to retrieve them all... (if an asset is depreciated there wont be anymore records relating that asset in that table) I'm sorry if this is confusing, I'll try my best to explain The report needs to have for each supplier registered a list of the assets that supplies, their description, their current location, it's price, and how much money still needs to be depreciated from the asset. So, what I'm doing it's first getting the list of suppliers, then getting the list of assets associated with a location (Using cursors) then I try to calculate how much money needs to be depreciated, there's a table called 'DEPRECIACIONES' that stores the asset, the period, and how much money has been depreciated from that asset for each period and for each asset that hasn't been completely depreciated. The problem comes when I try to calculate the MAX amount of money depreciated for an asset and then selecting the row for that item that has that MAX amount, I'm sure i'm doing something wrong, my TSQL and general database knowledge is not good and I'm trying to learn by myself. I've uploaded the schema, tables and the stored procedure that throws the wrong output here: http://sqlfiddle.com/#!3/78c32 The Right output should be something like this: Proveedor | Activo | Descripcion | Ubicacion Actual | Costo Adquisicion | Saldo sin depreciar | Periodo Supplier | Asset | Description | Current Location | Cost | Money to be depreciated | Period ------------------------------------------------------------------------------------------- Monse |ActivoT| texthere | 1114 |2034.50| RANDOM NUMBER HERE |RandomP Monse |cesart | texthere | 4453 |4553.50| RANDOM NUMBER HERE |RandomP nowlast | activ | texthere | 4453 |1234.65| RANDOM NUMBER HERE |RandomP nowlast |augusto| texthere | 4450 |4553.50| RANDOM NUMBER HERE |RandomP Sara |Activo | texthere | 1206 |746.65 | RANDOM NUMBER HERE |RandomP I'd really appreciate telling me what i'm doing wrong (which is probably a lot) and how to fix it, thank you in advance.
Good skills in giving complete information via SqlFiddle. I don't have a complete answer for you, but this may help. Firstly, ditch the cursor - it's hard to debug and possibly slow. Refactor to a SELECT statement. This is my attempt, which should be logically equivalent to your code: SELECT p.Proveedor, a.Activo, a.Descripcion, Ubi.Ubicacion, saldo_sin_depreciar = a.Costo_adquisicion - d.Monto_acumulado, d.Periodo FROM PROVEEDORES p INNER JOIN ACTIVOS_FIJOS a ON a.Proveedor = p.Proveedor INNER JOIN DEPRECIACIONES d ON a.Activo = d.Activo INNER JOIN ( SELECT MAX(d1.Monto_acumulado) AS MaxMonto FROM DEPRECIACIONES d1 INNER JOIN DEPRECIACIONES d2 ON d1.Monto_acumulado = d2.Monto_acumulado ) MaxAe ON d.Monto_acumulado = MaxAe.MaxMonto INNER JOIN ACTIVO_UBICACION Ubi ON a.activo = ubi.activo INNER JOIN ( SELECT activo, ubicacion, Fecha_Ubicacion, RowNum = row_number() OVER ( partition BY activo ORDER BY abs(datediff(dd, Fecha_Ubicacion, getdate()))) FROM ACTIVO_UBICACION ) UbU ON UbU.ubicacion = Ubi.Ubicacion WHERE -- a.Activo IS NOT NULL AND UbU.RowNum = 1 ORDER BY p.Proveedor COMMENTS I've moved the WHERE criteria that are defining the joins up into ON clauses in the table list, that makes it easier to see how you are joining the tables. Note that all the joins are INNER, which may not be what you want - you may need some LEFT JOIN's, I don't understand the logic enough to say. Also, in your cursor procedure the Ubi and UbU parts don't seem to explicitly join with the rest of the tables, so I've pencilled-in an INNER JOIN on the activo column, as this is the way the tables join in the FK relationship. In your cursor code, you would effectively get a CROSS JOIN which is probably wrong and also expensive to run. The WHERE clause a.Activo IS NOT NULL is not required, because the INNER JOIN ensures it. Hope this helps you sort it out.
I ended up using another query for the cursor and fixed the problem. It's probably not optimal but it works. Whenever I learn more database related stuff I'll optimize it. Here's the new query: DECLARE P CURSOR STATIC FOR SELECT a.Proveedor, actub.activo, actub.ubicacion FROM [SISACT].PROVEEDORES p,[SISACT].ACTIVOS_FIJOS a, (SELECT activo, ubicacion, Fecha_Ubicacion, row_number() OVER ( partition BY activo ORDER BY abs(datediff(dd, Fecha_Ubicacion, getdate())) ) AS RowNum FROM [SISACT].ACTIVO_UBICACION) actub WHERE RowNum = 1 AND a.Proveedor = p.Proveedor AND actub.activo = a.Activo OPEN P FETCH NEXT FROM P INTO #p, #a, #u WHILE ##FETCH_STATUS = 0 BEGIN SELECT #activo = a.Activo, #descripcion = a.Descripcion, #costo_adquisicion = a.Costo_adquisicion, #saldo_depreciado = MaxAe.MaxMonto, #periodo = d.Periodo FROM [SISACT].ACTIVOS_FIJOS a, [SISACT].DEPRECIACIONES d, SISACT.PROVEEDORES pro, SISACT.ACTIVO_UBICACION actu, (SELECT MAX(d1.Monto_acumulado) AS MaxMonto FROM [SISACT].DEPRECIACIONES d1 INNER JOIN [SISACT].DEPRECIACIONES d2 ON d1.Monto_acumulado = d2.Monto_acumulado WHERE d1.Activo = #a AND d2.Activo = #a) MaxAe WHERE a.Activo = d.Activo AND a.Activo = #a AND d.Activo = #a AND a.Proveedor = #p AND actu.Activo = #a AND actu.Ubicacion = #u SET #saldo_sin_depreciar = #costo_adquisicion - #saldo_depreciado FETCH NEXT FROM P INTO #p, #a, #u END CLOSE P DEALLOCATE P