Следует ли выбрать типы данных MONEY или DECIMAL(x,y) в SQL Server?

мне любопытно, есть ли реальная разница между money тип данных и что-то вроде decimal(19,4) (это то, что деньги используют внутри, я считаю).

Я знаю, что money относится к SQL Server. Я хочу знать, есть ли веская причина выбирать один из них; большинство образцов SQL Server (например, база данных AdventureWorks) используют money, а не decimal для таких вещей, как информация о цене.

должен ли я просто продолжать использовать тип данных money, или есть преимущество в использовании decimal вместо этого? Деньги меньше символов для ввода, но это не веская причина:)

12 ответов


никогда не следует использовать деньги. Это не точно, и это чистый мусор; всегда используйте decimal/numeric.

выполнить это, чтобы увидеть, что я имею в виду:

DECLARE
    @mon1 MONEY,
    @mon2 MONEY,
    @mon3 MONEY,
    @mon4 MONEY,
    @num1 DECIMAL(19,4),
    @num2 DECIMAL(19,4),
    @num3 DECIMAL(19,4),
    @num4 DECIMAL(19,4)

    SELECT
    @mon1 = 100, @mon2 = 339, @mon3 = 10000,
    @num1 = 100, @num2 = 339, @num3 = 10000

    SET @mon4 = @mon1/@mon2*@mon3
    SET @num4 = @num1/@num2*@num3

    SELECT @mon4 AS moneyresult,
    @num4 AS numericresult

выход: 2949.0000 2949.8525

некоторым людям, которые говорили, что вы не делите деньги на деньги:

вот один из моих запросов для вычисления корреляций, и изменение этого на деньги дает неправильные результаты.

select t1.index_id,t2.index_id,(avg(t1.monret*t2.monret)
    -(avg(t1.monret) * avg(t2.monret)))
            /((sqrt(avg(square(t1.monret)) - square(avg(t1.monret))))
            *(sqrt(avg(square(t2.monret)) - square(avg(t2.monret))))),
current_timestamp,@MaxDate
            from Table1 t1  join Table1 t2  on t1.Date = traDate
            group by t1.index_id,t2.index_id

SQLMenace сказал, что деньги неточны. Но вы не умножаете/делите деньги на деньги! Сколько стоит 3 доллара умножить на 50 центов? 150 dollarcents? Вы умножаете / делите деньги на скаляры, которые должны быть десятичными.

DECLARE
@mon1 MONEY,
@mon4 MONEY,
@num1 DECIMAL(19,4),
@num2 DECIMAL(19,4),
@num3 DECIMAL(19,4),
@num4 DECIMAL(19,4)

SELECT
@mon1 = 100,
@num1 = 100, @num2 = 339, @num3 = 10000

SET @mon4 = @mon1/@num2*@num3
SET @num4 = @num1/@num2*@num3

SELECT @mon4 AS moneyresult,
@num4 AS numericresult

результаты в правильном результате:

moneyresult           numericresult
--------------------- ---------------------------------------
2949.8525             2949.8525

money хорошо, если вам не нужно больше 4 десятичных цифр, и вы убедитесь, что ваши скаляры - которые не представляют деньги -decimals.


все опасно, если вы не знаете, что вы делаете

даже высокоточные десятичные типы не могут спасти день:

declare @num1 numeric(38,22)
declare @num2 numeric(38,22)
set @num1 = .0000006
set @num2 = 1.0
select @num1 * @num2 * 1000000

1.000000


на money типы являются целыми числами

текст представления smallmoney и decimal(10,4) могут выглядеть одинаково, но это не делает их взаимозаменяемыми. Вы съеживаетесь, когда видите даты, хранящиеся как varchar(10)? Это такая же вещь.

за кулисами money/smallmoney всего bigint/int десятичная точка в текстовом представлении money - это визуальный пух, как и тире в дате yyyy-mm-dd. SQL фактически не хранит их внутри.

о decimal vs money выбери все, что подходит для ваших нужд. The money типы существуют, потому что хранение учетных значений как целочисленных кратных 1 / 10000th единицы очень распространено. Кроме того, если вы имея дело с фактическими деньгами и расчетами за пределами простого сложения и вычитания, вы не должны делать это на уровне базы данных! сделать это на уровне приложения с библиотекой, обслуживающей округление банкира (IEEE 754)


Я понимаю, что WayneM заявил, что он знает, что деньги специфичны для SQL Server. Тем не менее, он спрашивает, Есть ли какие - либо причины использовать деньги через десятичную или наоборот, и я думаю, что одна очевидная причина все еще должна быть указана, и это использование десятичных средств-это одна вещь, о которой нужно беспокоиться, если вам когда-либо придется менять свою СУБД-что может произойти.

Сделайте ваши системы максимально гибкими!


Ну, мне нравится MONEY! Это байт дешевле DECIMAL, и вычисления выполняются быстрее, потому что (под обложками) операции сложения и вычитания по существу являются целочисленными операциями. Пример @SQLMenace,который является отличным предупреждением для неосознанных,может быть также применен к INTegers, где результат будет равен нулю. Но это не причина не использовать целые числа -где это уместно.

таким образом, это совершенно "безопасно" и подходит для использования MONEY когда вы имеете дело с MONEY и использовать его в соответствии с математическими правилами, которые следует (так же, как INTЭгер).

было бы лучше, если бы SQL Server способствовал делению и умножению MONEY ' s в DECIMALs (или FLOATs?)- возможно, но они не сделали этого; и они не решили продвигать INTэгерс к FLOATs при их разделении.

MONEY не имеет проблемы с точностью; это DECIMALs получить больший промежуточный тип используется во время вычислений-это просто "функция" использования этого типа (и я не уверен, насколько эта "функция" распространяется).

чтобы ответить на конкретный вопрос, "веская причина"? Ну, если вы хотите абсолютную максимальную производительность в SUM(x) здесь x может быть DECIMAL или MONEY, потом MONEY будет иметь преимущество.

кроме того, не забывайте, что это меньший кузен, SMALLMONEY - всего 4 байта, но он делает максимум на 214,748.3647 - что довольно мало для денег и так не часто подходит.

чтобы доказать точку вокруг использования больших промежуточных типов, если вы явно назначаете промежуточное значение переменной,DECIMAL страдает той же проблемой:

declare @a decimal(19,4)
declare @b decimal(19,4)
declare @c decimal(19,4)
declare @d decimal(19,4)

select @a = 100, @b = 339, @c = 10000

set @d = @a/@b

set @d = @d*@c

select @d

производит 2950.0000 (хорошо, по крайней мере DECIMAL округлый, а не MONEY truncated-то же, что и целое число.)


в качестве контрапункта к общей направленности других ответов. См.многие преимущества денег ... тип данных! на руководство SQLCAT по реляционному движку

в частности, я бы отметил следующее

работая над реализациями клиентов, мы нашли некоторые интересные номера производительности, касающиеся типа данных money. Например, когда Службам Analysis Services был присвоен тип данных валюты (от double) до матч в SQL Тип данных денег сервера, было улучшение 13% в скорость обработки (строки / сек). Для повышения производительности в SQL Службы Server Integration Services (SSIS) для загрузки 1.18 ТБ менее чем за тридцать протокол, как отмечается в SSIS 2008-world record ETL performance, был замечено, что изменение четырех десятичных (9,2) столбцов с размером 5 байты в таблице LINEITEM TPC-H к деньгам (8 байтов) улучшенная масса скорость вставки 20% ... Причиной повышения производительности является SQL Протокол табличного потока данных (TDS) сервера, который присвоен основной принцип конструкции для передачи данных в компактном двоичном виде и как можно ближе к внутренней памяти формат SQL Server. Эмпирически это наблюдалось во время SSIS 2008-world record ETL performance test с использованием Kernrate; протокол значительно упал, когда тип данных был переключен на деньги из decimal. Это делает передача данных максимально эффективна. Сложный тип данных требует дополнительного анализа и циклы CPU для обработки, чем тип фиксированной ширины.

поэтому ответ на вопрос - "это зависит". Вам нужно быть более осторожным с некоторыми арифметическими операциями, чтобы сохранить точность, но вы можете обнаружить, что соображения производительности делают это стоящим.


мы только что столкнулись с очень похожей проблемой, и теперь я очень +1 за то, что никогда не использую деньги, кроме как в презентации верхнего уровня. У нас есть несколько таблиц (фактически ваучер продажи и счет продажи), каждая из которых содержит одно или несколько полей денег по историческим причинам, и нам нужно выполнить пропорциональный расчет, чтобы выяснить, какая часть общего налога по счету имеет отношение к каждой строке ваучера продажи. Наш расчет

vat proportion = total invoice vat x (voucher line value / total invoice value)

это приводит к реальному миру расчет денег / денег, который вызывает ошибки масштаба на части деления, которая затем умножается на неправильную долю НДС. Когда эти значения впоследствии добавляются, мы получаем сумму пропорций НДС, которые не складываются в общую стоимость счета-фактуры. Если бы любое из значений в скобках было десятичным (я собираюсь привести одно из них как таковое), пропорция НДС была бы правильной.

когда скобок не было изначально, это использовалось для работы, я думаю, из-за чем больше значения, тем эффективнее имитируется более высокая шкала. Мы добавили скобки, потому что он сначала делал умножение, которое в некоторых редких случаях подрывало точность, доступную для расчета, но теперь это вызвало эту гораздо более распространенную ошибку.


Я хочу дать другой взгляд на деньги против численного, в основном на основе моего собственного опыта и опыта... Моя точка зрения здесь-деньги, потому что я работал с ними в течение значительного времени и никогда особо не использовал числовые...

деньги Pro:

  • Собственный Тип Данных. Он использует собственный тип данных (целое) так же, как регистр процессора (32 или 64 бит), поэтому расчет не требует ненужных накладных расходов так это меньше и быстрее... Деньги нуждаются в 8 байтах, а числовые (19, 4) - в 9 байтах (на 12,5% больше)...

    деньги быстрее, пока он используется для того, чтобы он должен был быть (как деньги). Как быстро? Мой простой SUM тест на 1 миллион данных показывает, что деньги 275 МС и числовой 517 МС... Это почти в два раза быстрее... Почему тест SUM? Смотрите далее Pro точка

  • лучший за деньги. Деньги лучше всего хранить деньги и делать операции, например, в бухгалтерии. Один отчет может запускать миллионы сложений (SUM) и несколько умножений после выполнения операции SUM. Для очень больших бухгалтерских приложений это почти в два раза быстрее, и это чрезвычайно важно...
  • низкая точность денег!--10-->. Деньги в реальной жизни не должны быть очень точными. Я имею в виду, многие люди могут заботиться о 1 cent USD, но как насчет 0.01 cent USD? На самом деле, в моя страна, банки больше не заботятся о центах (цифра после десятичной запятой); я не знаю о банке США или другой стране...

деньги Con:

  • Ограниченную Точность. Деньги имеют только четыре цифры (после запятой) точность, поэтому он должен быть преобразован перед выполнением таких операций, как разделение... Но опять же money Не нужно быть настолько точен и предназначен для использования в качестве денег, а не просто номер...

но... Большой, но вот даже в вашем приложении задействованы реальные деньги, но не используйте его во множестве суммовых операций, как в бухгалтерии. Если вы используете много делений и умножения вместо этого, то вы не должны использовать деньги...


вы не должны использовать деньги, когда вам нужно делать умножения / деления на значение. Деньги хранятся так же, как целое число, тогда как десятичное число хранится как десятичная точка и десятичные цифры. Это означает, что деньги в большинстве случаев снижают точность, в то время как decimal будет делать это только при преобразовании обратно в исходную шкалу. Деньги-это фиксированная точка, поэтому ее масштаб не меняется во время расчетов. Однако, поскольку это фиксированная точка, когда она печатается как десятичная строка (как в отличие от фиксированной позиции в базовой строке 2), значения до масштаба 4 представлены точно. Так что для сложения и вычитания деньги-это нормально.

десятичное число представлено в базе 10 внутренне, и, таким образом, позиция десятичной точки также основана на числе базы 10. Что делает его дробную часть точно представлять свою ценность, так же, как с деньгами. Разница в том, что промежуточные значения decimal могут поддерживать точность до 38 десятичные знаки.

с числом с плавающей запятой значение хранится в двоичном формате, как если бы оно было целым числом, а десятичная (или двоичная, ГМ) точка находится относительно битов, представляющих число. Поскольку это двоичная десятичная точка, базовые 10 чисел теряют точность сразу после десятичной точки. 1 / 5th или 0.2 не могут быть представлены именно таким образом. Ни деньги, ни десятичные числа не страдают от этого ограничения.

достаточно легко конвертировать деньги в десятичную, выполните вычисления,а затем сохраните полученное значение обратно в денежное поле или переменную.

из моего POV я хочу, чтобы вещи, которые происходят с числами, просто происходили, не задумываясь о них. Если все вычисления будут преобразованы в decimal, то для меня я просто хочу использовать decimal. Я бы сохранил денежное поле для показа.

размер-мудрый я не вижу достаточно разницы, чтобы передумать. Деньги занимают 4-8 байт, тогда как десятичное число может быть 5, 9, 13 и 17. 9 байтов могут покрывать весь диапазон, который могут 8 байтов денег. Index-wise (сравнение и поиск должны быть сопоставимы).


Я нашел причину использования decimal над деньгами в теме точности.

DECLARE @dOne   DECIMAL(19,4),
        @dThree DECIMAL(19,4),
        @mOne   MONEY,
        @mThree MONEY,
        @fOne   FLOAT,
        @fThree FLOAT

 SELECT @dOne   = 1,
        @dThree = 3,    
        @mOne   = 1,
        @mThree = 3,    
        @fOne   = 1,
        @fThree = 3

 SELECT (@dOne/@dThree)*@dThree AS DecimalResult,
        (@mOne/@mThree)*@mThree AS MoneyResult,
        (@fOne/@fThree)*@fThree AS FloatResult

просто проверить его и принять решение.


Я только что видел эту запись в блоге:деньги против Decimal в SQL Server.

который в основном говорит, что деньги имеют точный вопрос...

declare @m money
declare @d decimal(9,2)

set @m = 19.34
set @d = 19.34

select (@m/1000)*1000
select (@d/1000)*1000

на money типа, вы получите 19.30 вместо 19.34. Я не уверен, есть ли сценарий приложения, который делит деньги на 1000 частей для расчета, но этот пример раскрывает некоторые ограничения.


все предыдущие сообщения приносят действительные очки, но некоторые не отвечают на вопрос точно.

вопрос: почему кто-то предпочитает деньги, когда мы уже знаем, что это менее точный тип данных и может вызвать ошибки при использовании в сложных расчетах?

вы используете деньги, когда вы не будете делать сложные вычисления и можете торговать этой точностью для других нужд.

например, когда вам не нужно делать эти вычисления выше и вам нужно сохранить 1 байт (деньги занимают 8 байт, а decimal (19,4) занимает 9 байт).

другой пример, когда вам не нужно делать эти вычисления выше и нужна скорость для обработки огромного количества данных.

другой пример, когда вам не нужно делать эти вычисления выше, и вам нужно импортировать из допустимых текстовых строк валюты. Попробуйте сделать это с другими числовыми типами: выберите конвертировать(деньги, '$1,000.68')