2015-04-14 43 views
1

我有一组具有以下结构表中多次重复:更好的性能

Sign|Value 
    |1000 
    -|1000 

所以有一种“符号”栏后面的“值”列...并且这两个值都是varchar(..)。我从这个基础数据构建表,并希望使用符号转换为十进制。

目前我一直在做以下几点:

CASE 
    WHEN LTRIM(RTRIM(s.PreviousPointBalanceSign)) = '-' 
    THEN -1 * CAST(s.PreviousPointBalance AS decimal(14,2)) 
    ELSE CAST(s.PreviousPointBalance AS decimal(14,2)) 
END AS PreviousPointBalance 

但我想知道如果用函数来实现,这将让我更好的性能?

+1

为什么表格首先具有此结构?与简单地将'-1000'存储为'decimal(14,2)''相反? –

+2

如果是您以后的表现,则将数据存储在适当的数据类型中。为了回答你的问题,你将通过标量函数使用CASE表达式来获得更好的性能。如果您使用内联TVF而不是标量函数,如[Itzik Ben-Gan的本文](http://sqlmag.com/sql-server/inline-scalar-functions)中所述,那么函数的性能而且由于函数的定义只是简单地扩展到主查询中,因此case表达式将完全相同。 – GarethD

+0

'CASE'声明比'SCALAR'函数更好的执行者。 –

回答

0

您打算使用哪种功能?基本功能对性能没有帮助。它们简化了代码,它们使您能够重新使用代码等等。普通的SQL将永远更好或相同。在你的情况下,最好的解决方案是以适当的方式存储数据,但是如果不可能,那就试着用不同的方法做同样的事情。例如:

1) CASE WHEN Sign like '%-%'; 
    2) CASE WHEN LEN(Sign) > 0. 
3) You can also avoid CASE at all: SELECT CAST(Value AS Decimal(14,2)) * ((-1 + (LEN(Sign)^1) * 2)) 

您还可以使用计算的持续列来计算插入时的值。

UPD:

后小试验,优化出绝对相同的计划,所有的方式:

CREATE TABLE #test 
(
     value VARCHAR(3), 
    [sign] VARCHAR(3) 

); 

DECLARE @a INT = 0; 
WHILE (@a < 1000) 
BEGIN 
INSERT INTO #test VALUES (CAST(@a AS VARCHAR(100)), CASE WHEN @a%2 =0 THEN '-' ELSE '' END) 
SET @[email protected]+1; 

END 


SELECT 
CASE 
    WHEN LTRIM(RTRIM(s.[sign])) = '-' 
    THEN -1 * CAST(s.value AS decimal(14,2)) 
    ELSE CAST(s.value AS decimal(14,2)) 
END AS PreviousPointBalance 
FROM #test s 

SELECT 
CASE 
    WHEN s.[sign] LIKE '%-%' 
    THEN -1 * CAST(s.value AS decimal(14,2)) 
    ELSE CAST(s.value AS decimal(14,2)) 
END AS PreviousPointBalance 
FROM #test s 

SELECT 
CASE 
    WHEN LEN(s.sign) >0 
    THEN -1 * CAST(s.value AS decimal(14,2)) 
    ELSE CAST(s.value AS decimal(14,2)) 
END AS PreviousPointBalance 
FROM #test s 

SELECT CAST(Value AS Decimal(14,2)) * ((-1 + (LEN(Sign)^1) * 2)) AS PreviousPointBalance 
FROM #test s 
1

显然,最好的选择是你的两列转换成一个,但因为这是不是一种选择。我认为你卡住了。如果你可以改变你的表并且使[符号]字符(1),你将有每行少2个字节。你有2500万行* 2字节= 50MB。所以缩小这应该至少有一点帮助。

就功能而言,我不知道是否有更快的方法来做到这一点。还有一个更简单的方法,虽然像这样:

SELECT CAST(CONCAT(RTRIM([sign]),value) AS DECIMAL(14,2)) AS PreviousPointBalance 
FROM yourTable 

你只需要RTRIM(),因为SQL Server不关心周围的VARCHAR空间将被强制转换为十进制。如果您要将表格更改为CHAR(1),则您甚至不必担心RTRIM()

SELECT CAST(' -99 ' AS DECIMAL(14,2)) --works 
SELECT CAST('- 99 ' AS DECIMAL(14,2)) --fails