Як просте припущення про ISNULL і COALESCE мало не зруйнувало фінансовий стартап
Впевненість, яка майже коштувала всього
«ISNULL і COALESCE? Вони обидві замінюють NULL значення.То в чому проблема? Вони однакові».
Саме це я сказав керівнику своєї команди під час перегляду коду три роки тому.Я був впевнений, навіть зневажливо самовпевненй. Адже я використовував SQL роками. Ці функції були базовими.
Мій тімлід просто кивнув і схвалив merge (обʼєднання гілок).
Через шість місяців ця впевненість майже довела нашого клієнта до банкрутства.
День, коли все зруйнувалося
Все почалося як звичайний вівторок. Я попивав ранкову каву, коли Slack вибухнув панічними повідомленнями:
«У щомісячному фінансовому звіті вказані неправильні цифри!» «Розрахунки доходів не відповідають дійсності на сотні тисяч!» «За 2 години зустріч з клієнтом, ПОТРІБНО НЕВІДКЛАДНО ВИПРАВИТИ!»
Звіт, який бездоганно працював протягом місяців, раптом почав видавати суперечливі дані. Деякі суми були округлені, в інших повністю бракувало десяткових знаків. Наш клієнт, зростаючий стартап у сфері фінансових технологій, мав представити ці цифри потенційним інвесторам.
Що найстрашніше? У нашому коді змінилося лише одне.
Я «оптимізував» один рядок:
-- Original working code
SELECT COALESCE(Amount, 0) FROM FinancialTransactions;
-- My "improvement"
SELECT ISNULL(Amount, 0) FROM FinancialTransactions;
«ISNULL працює швидше на SQL Server», — міркував я. «Та сама функціональність, краща продуктивність».
Я був абсолютно неправий.
Момент жахливої ясності
Коли я відчайдушно намагався виправити цю проблему, правда вразила мене, як вантажний потяг. Дозвольте мені показати вам, що саме відбувалося:
Структура нашого столу
CREATE TABLE FinancialTransactions (
TransactionID INT,
CustomerID INT,
Amount DECIMAL(10,2), -- Notice: DECIMAL with 2 decimal places
TransactionDate DATE
);
-- Sample data
INSERT INTO FinancialTransactions VALUES
(1, 101, 1234.56, '2024-01-15'),
(2, 102, NULL, '2024-01-16'), -- NULL value here!
(3, 103, 987.89, '2024-01-17');
Що робила компанія COALESCE (правильний підхід)
SELECT
TransactionID,
COALESCE(Amount, 0) AS CleanAmount
FROM FinancialTransactions;
Результати:
TransactionID CleanAmount
1 1234.56 -- Precision maintained
2 0.00 -- NULL replaced, precision kept
3 987.89 -- Original precision preserved
Що робив ISNULL (катастрофа)
SELECT
TransactionID,
ISNULL(Amount, 0) AS CleanAmount
FROM FinancialTransactions;
Результати:
TransactionID CleanAmount
1 1234 -- Lost decimal places!
2 0 -- NULL replaced but wrong type
3 987 -- Truncated!
Руйнівна різниця: ISNULL перетворювала наші точні фінансові дані на цілі числа, втрачаючи всю інформацію про десяткові знаки.
Технічна реальність, яку я пропустив
Ось що я не зрозумів про ці «ідентичні» функції:
ISNULL: зберігач типів (своєрідний)
-- ISNULL uses the data type of the replacement value
DECLARE @Amount DECIMAL(10,2) = NULL;
SELECT ISNULL(@Amount, 0); -- Result becomes INT because 0 is INT
ISNULL перевіряє значення заміни (0) і каже: «Ви дали мені ціле число, тому я поверну ціле число». Йому байдуже, що ваш оригінальний стовпець був десятковим.
COALESCE: промоутер типів
-- COALESCE picks the highest precedence data type
DECLARE @Amount DECIMAL(10,2) = NULL;
SELECT COALESCE(@Amount, 0); -- Result stays DECIMAL(10,2)
COALESCE перевіряє всі аргументи і перетворює результат у тип даних з найвищим пріоритетом. Оскільки DECIMAL має вищий пріоритет, ніж INT, вона зберігає нашу точність.
Вплив на реальний світ
Давайте розглянемо це в перспективі. Щомісячний звіт про доходи нашого клієнта показав:
З COALESCE (правильно):
- Транзакція 1: 1 234,56 доларів США
- Транзакція 2: 0,00 доларів США
- Транзакція 3: 987,89 доларів США
- Разом: 2 222,45 доларів
З ISNULL (неправильно):
- Транзакція 1: 1 234 долари
- Транзакція 2: 0 доларів
- Транзакція 3: 987 доларів
- Разом: 2 221 доларів
Помножте це на понад 50 000 щомісячних транзакцій, і ми «втрачали» тисячі доларів у заявлених доходах. Не реальні гроші, а точність, від якої залежать фінансові системи.
Коли ця відмінність стає критичною
Це не просто теоретична проблема. Ось реальні ситуації, з якими я стикався:
Фінансові розрахунки
-- Interest rate calculations
SELECT
AccountID,
COALESCE(InterestRate, 0.0000) * Balance AS Interest -- ✅ Maintains precision
FROM Accounts;
-- Wrong approach that loses precision
SELECT
AccountID,
ISNULL(InterestRate, 0) * Balance AS Interest -- ❌ Converts to INT
FROM Accounts;
Показники ефективності
-- API response times in milliseconds
SELECT
RequestID,
COALESCE(ResponseTime, 0.000) AS ResponseTimeMS -- Keeps 3 decimal precision
FROM APILogs;
Наукові дані
-- Temperature measurements
SELECT
SensorID,
COALESCE(Temperature, 0.00) AS TempCelsius -- Preserves decimal accuracy
FROM SensorReadings;
Міф про продуктивність, у який я вірив
«Але ISNULL працює швидше!» — повторював я собі під час панічного виправлення.
Так, ISNULL може бути швидшим — за умови правильного використання:
-- When data types match exactly, ISNULL wins
SELECT ISNULL(CustomerName, 'Unknown') FROM Customers; -- Both are VARCHAR
Але коли ви маєте невідповідності типів, COALESCE не тільки безпечніша — вона часто є більш продуктивною, оскільки дозволяє уникнути неявних перетворень:
-- COALESCE avoids conversion overhead
SELECT COALESCE(Amount, 0.00) FROM Transactions; -- No conversion needed
-- ISNULL forces conversion
SELECT ISNULL(Amount, 0) FROM Transactions; -- Converts DECIMAL to INT
Моя система прийняття рішень зараз
Після цього дорогого уроку ось як я вибираю між ними:
Використовуйте ISNULL, коли:
- Типи даних ідентичні
- Робота виключно з SQL Server
- Продуктивність має вирішальне значення
- Прості двозначні сценарії
Використовуйте COALESCE, коли:
- Будь-які сумніви щодо типів даних (найважливіше!)
- Потрібні кілька резервних значень
- Необхідна сумісність між базами даних
- Фінансові дані або дані, що мають критичне значення для точності (завжди!)
Екстрене виправлення
Рішення було напрочуд простим, коли я зрозумів суть проблеми:
-- Замість несправної версії
SELECT ISNULL(Amount, 0) AS CleanAmount
-- Виправлена версія з правильним написанням
SELECT ISNULL(Amount, 0.00) AS CleanAmount
-- Або ще краще
SELECT COALESCE(Amount, 0.00) AS CleanAmount
Ключове спостереження: при використанні ISNULL значення заміни повинно точно відповідати типу даних оригінального стовпця.
Перевірка вашого розуміння
Спробуйте цю швидку вправу:
DECLARE @Price MONEY = NULL;
DECLARE @Discount DECIMAL(5,2) = NULL;
-- Що тут відбувається?
SELECT ISNULL(@Price, 5); -- Тип результату?
SELECT COALESCE(@Price, 5); -- Тип результату?
SELECT ISNULL(@Discount, 10); -- Тип результату?
SELECT COALESCE(@Discount, 10); -- Тип результату?
Відповіді:
- ISNULL(@Price, 5): Повертає 5 як INT (втрачається точність типу MONEY!)
- COALESCE(@Price, 5): Повертає 5,00 як MONEY (зберігає точність)
- ISNULL(@Discount, 10): Повертає 10 як INT (втрачається точність типу DECIMAL!)
- COALESCE(@Discount, 10): Повертає 10,00 як DECIMAL(5,2) (зберігає точність)
Більш важливий урок про припущення
Цей випадок навчив мене важливому уроку: у розробці програмного забезпечення найнебезпечнішим припущенням часто є те, що «вони роблять те саме».
Я навчився ставити різні питання:
- «Чи однаково вони поводяться з граничними випадками?»
- «А як щодо поведінки типів даних?»
- «Чи є якісь тонкі відмінності, які я пропускаю?»
- «Що відбувається за різних умов?»
Відповідь клієнта
Після того, як ми виправили проблему і пояснили, що сталося, технічний директор нашого клієнта сказав щось, що я ніколи не забуду:
«Я ціную вашу чесність щодо помилки. Але ще більше мене вражає те, як швидко ви діагностували першопричину і впровадили запобіжні заходи, щоб запобігти її повторенню».
Ми не втратили клієнта. Навпаки, через шість місяців вони подвоїли обсяг контракту, назвавши нашу увагу до цілісності даних ключовим фактором.
Ключові висновки для вашої кар’єри
- Питання «очевидних» подібностей -Схожа функціональність не означає ідентичну поведінку
- Глибоко розумійте типи даних — це не просто академічні поняття
- Тестування з використанням реалістичних даних —граничні випадки, що виникають у виробництві
- Документуйте своє міркування – допоможіть майбутнім розробникам зрозуміти ваші рішення
- Ретельно вчіться на помилках – перетворюй дорогі уроки на цінні знання
Перегляд коду, який змінив усе
Тепер, коли я бачу ISNULL і COALESCE під час перевірки коду, я задаю одне просте питання:
«Чи є типи даних усіх аргументів ідентичними?»
Якщо є якісь сумніви, я рекомендую COALESCE. Справа не тільки в правильності, а й у запобіганні надзвичайних дзвінків о 2 годині ночі, які можуть зруйнувати кар’єру і компанію.
Озираючись назад
Ця «проста оптимізація» навчила мене, що дрібні деталі SQL можуть дійсно зруйнувати великі системи. Різниця між джуніором і сініором полягає не в уникненні помилок, а в усвідомленні наслідків своїх рішень ще до їхнього впровадження в продакшн.
ISNULL і COALESCE на перший погляд можуть здаватися однаковими. Але під капотом деталі мають значення. Завжди.
Про автора: Я інженер з даних, який навчився SQL важким шляхом через виробничі збої та аварійні виправлення о 3 годині ночі. Зробивши всі можливі помилки з базами даних, я тепер ділюся цими дорогими уроками, щоб допомогти іншим уникнути тих самих помилок. Моя місія проста: перетворити болісний досвід на цінне навчання для спільноти, що працює з даними.
Якщо ця інформація була для вас корисною, підпишіться на мене, щоб отримувати більше цікавих відомостей про інженерію даних, розвиток кар’єри та уроки, винесені з практичного досвіду побудови систем даних. 🚀
Зв’яжіться зі мною: 🔗
- LinkedIn: www.linkedin.com/in/sahil-alam-680986173/ 💼
- Medium:Sahil Alam ✍️
Статті, які можуть вам сподобатися: 📚
- “🚨 Чому я провалив співбесіди з інженерії даних (і як я це виправив) 🔧”
- “🛠️ Чому ваша перша робота в сфері технологій здається нудною (і чому це добре) 🚀”
- “💭 Одне інтерв’ю-питання назавжди змінило мій підхід до написання SQL”
Теги: #DataEngineering #TechInterviews #CareerAdvice #DataEngineer #InterviewTips #SystemDesign #BigData #DataCareers #TechCareers #JobSearch #DataScience #Analytics #CareerGrowth #TechSkills #InterviewPrep
ОРИГІНАЛ СТАТТІ:💡 The $2M SQL Mistake: Why I’ll Never Forget the Difference Between
АВТОР СТАТІ:Sahil AlamISNULLandCOALESCE
🚀Долучайтесь до нашої спільноти Telegram:
🚀Долучайтесь до нашої спільноти FaceBook:
🚀Долучайтесь до нашої спільноти Twiter X:
