August 1, 2005 at 1:04 pm
this is sort of a hot one right now. I'm hoping another set of eyes might see something I'm not seeing. What kinds of other info can I offer? How about table counts for significants:
select count(*) from dbo.fnPositionS(null)
4911
select count(*) from tbMark
484658
select count(*) from tbDataset
1351
select count(*) from tbInstTranche
2215
select count(*) from tbInst
2099
declare @InstCompanyName varchar(255)
set @InstCompanyName = 'YAGEO'
select
Strategy= S.BizStrategyName,
Ticker= I.SevernTicker + ITT.EnumName,
Quantity= sum(P.Quantity),
Price= convert(decimal(20,2), M.Price),
Currency= right(C.InstCurrencyName, 3),
FXRate= FX.Price,
MarketValue= sum(dbo.fnPosMarketValue(P.Quantity, M.Price, I.PriceFactor, I.InstTypeEnumID, FX.Price, C.IsQuotedInverse))
from
dbo.fnPositionS(null) P
jointbInstTranche IT on P.InstTrancheID = IT.InstTrancheID
jointbInst I on IT.InstID = I.InstID
jointbEnum ITT on IT.InstTrancheTypeEnumID = ITT.EnumID
jointbBizStrategy S on P.BizStrategyID = S.BizStrategyID
left join tbMark M on I.InstID = M.InstID -- and M.MarkSourceEnumID = dbo.fnEnumS('MarkSource', 'EOD')
left join tbInstCurrency C on M.InstCurrencyID = C.InstCurrencyID
left join tbMark FX on C.InstCurrencyID = FX.InstID and FX.InstCurrencyID = 10
left join tbDataset D on D.DatasetID = M.DatasetID
jointbInstCompany IC on I.InstCompanyID = IC.InstCompanyID
where
I.InstTypeEnumID != dbo.fnEnumS('InstType', 'cy')
and IC.InstCompanyName = @InstCompanyName
and DatasetTypeEnumID = dbo.fnEnumS('DatasetType','MEOD')
group by
S.BizStrategyName,
I.SevernTicker + ITT.EnumName,
M.Price,
C.InstCurrencyName,
C.IsQuotedInverse,
FX.Price
having
sum(Quantity) != 0
order by
S.BizStrategyName,
I.SevernTicker + ITT.EnumName
August 1, 2005 at 1:23 pm
Can you post the definition of:
1. dbo.fnEnumS
2. dbo.fnPosMarketValue
and
does the Quantity value can be negative ?
* Noel
August 1, 2005 at 1:28 pm
both are used in too many other stored code objects without consequence. They're quick and inconsequential. fnEnumS is a lookup translator and fnPosMarketValue just does some simple math.
create function fnEnumS (@EnumTypeName dtString, @EnumName dtString)
returns int
as
begin
declare @EnumID int
select @EnumID = E.EnumID
from tbEnum E
join tbEnumType ET on ET.EnumTypeID = E.EnumTypeID and ET.EnumTypeName = @EnumTypeName
where
E.EnumName = @EnumName
return (@EnumID)
end
create function fnPosMarketValue(
@QuantitydtQuantity,
@Pricefloat,
@PriceFactorfloat,
@InstTypeEnumID int,
@FXRatefloat,
@IsQuotedInversebit) returns float
as
begin
return@Quantity * @PriceFactor * isnull(case when @IsQuotedInverse = 1 then @FXRate else 1 / @FXRate end, 1) * @Price
end
August 1, 2005 at 1:49 pm
>> They're quick and inconsequential <<
Functions are never inconsequential They force row by row processing in many cases, instead of set based and therefore should be used sparingly (meaning small sets or single call )
can you try:
declare @InstCompanyName varchar(255)
set @InstCompanyName = 'YAGEO'
select
Strategy = S.BizStrategyName,
Ticker = I.SevernTicker + ITT.EnumName,
Quantity = sum(P.Quantity),
Price = convert(decimal(20,2), M.Price),
Currency = right(C.InstCurrencyName, 3),
FXRate = FX.Price,
MarketValue = sum(P.Quantity * I.PriceFactor * isnull(case when C.IsQuotedInverse = 1 then FX.Price else 1 / FX.Price end, 1) * M.Price)
from
dbo.fnPositionS(null) P
join tbInstTranche IT on P.InstTrancheID = IT.InstTrancheID
join tbInst I on IT.InstID = I.InstID and
join tbEnum ITT on IT.InstTrancheTypeEnumID = ITT.EnumID
join tbBizStrategy S on P.BizStrategyID = S.BizStrategyID
left join tbMark M on I.InstID = M.InstID -- and M.MarkSourceEnumID = dbo.fnEnumS('MarkSource', 'EOD')
left join tbInstCurrency C on M.InstCurrencyID = C.InstCurrencyID
left join tbMark FX on C.InstCurrencyID = FX.InstID and FX.InstCurrencyID = 10
left join tbDataset D on D.DatasetID = M.DatasetID
join tbInstCompany IC on I.InstCompanyID = IC.InstCompanyID
where
I.InstTypeEnumID != dbo.fnEnumS('InstType', 'cy')
and IC.InstCompanyName = @InstCompanyName
and DatasetTypeEnumID = dbo.fnEnumS('DatasetType','MEOD')
-- If Quantity cannot be < 0 add this:
-- and Quantity > 0
group by
S.BizStrategyName,
I.SevernTicker + ITT.EnumName,
M.Price,
C.InstCurrencyName,
C.IsQuotedInverse,
FX.Price
having
sum(Quantity) != 0
order by
S.BizStrategyName,
I.SevernTicker + ITT.EnumName
check to see if you get index seeks on I.InstTypeEnumID and and DatasetTypeEnumID . If you do then don't need to do anything about the enum function if you don't then you will have to replace the function with a join
hth
* Noel
August 1, 2005 at 2:24 pm
get this... Index Wizard came through! 2 nonclustereds did the trick. one for Inst, one for Mark.
CREATE NONCLUSTERED INDEX [tbMark28] ON [dbo].[tbMark] ([InstID] ASC, [InstCurrencyID] ASC, [DatasetID] ASC, [Price] ASC )
CREATE NONCLUSTERED INDEX [tbInst31] ON [dbo].[tbInst] ([InstID] ASC, [InstCompanyID] ASC, [SevernTicker] ASC, [InstTypeEnumID] ASC, [PriceFactor] ASC )
there's a first time for everything, eh?
thanks for the help Noel.
August 1, 2005 at 2:37 pm
Glad you work it out. I should have started asking for the indexes utilization in the first place
* Noel
August 2, 2005 at 12:43 am
The row-based , set-based thing just confuses matters.
Indexes (in SQL Server) are on the column values, when you have a criteria/predicate in a SELECT that has a function on it then SQL server has no choice but to do a full index scan and then run the function on all the rows and then retrieve the results for comparison; unless you have another criteria/predicate on another column on the same table that does not have a function on it, in which case it will use the index on the other column to retrieve the rows and run the function on that subset of rows only. This is of course provided that the other column is selective enough that the CBO decides to use the index instead of table scan (so adding a index on a column like gender won't help much).
Index scan although better than a table scan can still be very slow, what you really want in a typical OLTP system would be index seeks.
To achieve that, you can create a computed column with the function as the formula. For example ColumnA will be Function(ColumnA). And then create a index on the new computed column. Next in your SELECT statement(s), use the computed column instead of the original column.
But this only works for deterministic columns and there are other implications when insert/update. A search on Creating Indexes on Computed Columns in SQL Server Books Online will give you the full details.
Viewing 7 posts - 1 through 6 (of 6 total)
You must be logged in to reply to this topic. Login to reply