Azure SQL Database を新規に作成すると 「12.x」 と表示され、「SQL Server 2014 相当のままでは?」と不安になる方が少なくありません。さらに OR マッパーの Sequelize から “mssql 12.0 は非対応、14.0 以上を要求” といった警告が出ると、環境を作り直すべきか迷います。本記事では、この混乱の正体と正しい対処(=互換性レベルの設定)を、手順・検証・運用ノウハウまで実務目線で徹底解説します。
Azure SQL Database の「バージョンを上げたい」問題とは
まず結論から整理します。Azure SQL Database はクラウドのサービスとして提供されており、サーバー エンジン自体は常に最新安定版へと自動的に更新されています。ところが外部に公開されるバージョン情報は互換性維持の目的で簡略表記(v12 系)に固定されており、ここが誤解の出発点です。アプリ側で必要なのは「メジャーバージョン切り替え」ではなく、互換性レベル(compatibility level)の調整です。
よくある誤解と正しい理解(要点まとめ)
| 誤解しやすい点 | 正しい仕組み・対処方法 |
|---|---|
| 「12.x」は SQL Server 2014 固定で古い | Azure SQL Database は エンジンが常に最新安定版に自動更新される。外部 API/関数は互換性のため v12 という系統だけを報告する設計。 |
| v14・v16 などを自分で選ぶ必要がある | 選べるのは 互換性レベル(COMPATIBILITY_LEVEL)。T‑SQL 機能やクエリ最適化の振る舞いを 2008 → 2022 相当まで切り替え可能。 |
| Sequelize の「12.0 は非対応」警告は重大 | Sequelize は @@VERSION や SERVERPROPERTY('ProductVersion') を文字列解析してメジャー判定するため、Azure では常に 12.x を拾って誤判定する。クラウド版 Azure SQL では 無視して問題なし。 |
なぜ Azure SQL Database は「12.x」と表示されるのか
オンプレミス製品の SQL Server は 2014(v12)、2016(v13)、2017(v14)、2019(v15)、2022(v16)というメジャーバージョンの系譜で語られます。一方、Azure SQL Database は PaaS(Platform as a Service)であり、サービス運営側が継続的にロールアウトする新機能や最適化を取り込み続ける “evergreen” なエンジンです。互換性確保のため外部には 「v12 系」という安定の識別を返す仕様になっており、これをそのまま解釈すると「古い」と錯覚します。
実際に次のようなクエリを実行すると、文字列の先頭は概ね以下のようになります。
SELECT @@VERSION AS VersionString;
SELECT SERVERPROPERTY('ProductVersion') AS ProductVersion,
SERVERPROPERTY('ProductLevel') AS ProductLevel,
SERVERPROPERTY('EngineEdition') AS EngineEdition; -- 5 = Azure SQL Database
ProductVersion は 12.x.xxxx といった形式ですが、EngineEdition は 5(=Azure SQL Database)を返します。つまり、「12」はオンプレのメジャーバージョンを指していないと理解してください。
互換性レベル(compatibility level)を理解する
Azure SQL Database でアプリケーションの振る舞いに直結する設定は「互換性レベル」です。これはクエリ最適化や一部の T‑SQL 機能の既定挙動を、過去バージョン相当に“擬態”させるためのスイッチです。新しい最適化を活かしたい時はレベルを上げ、古い挙動で安全に動かしたい時は下げます。
| 互換性レベル | 相当するオンプレ版 | 代表的なポイント |
|---|---|---|
| 100 | SQL Server 2008 | レガシー互換。新しい最適化は基本無効。 |
| 110 | SQL Server 2012 | 旧来アプリの互換維持に利用。 |
| 120 | SQL Server 2014 | 新しい CE(Cardinality Estimator)導入世代の境目。 |
| 130 | SQL Server 2016 | JSON 機能など多くの T‑SQL が実用域に。 |
| 140 | SQL Server 2017 | 自動チューニングの前提が整う。 |
| 150 | SQL Server 2019 | UDF インライン化、テーブル変数の遅延コンパイル、Rowstore へのバッチモードなど Intelligent Query Processing の大波。 |
| 160 | SQL Server 2022 | Parameter Sensitive Plan (PSP) など最新の最適化が有効化。 |
注意点として、関数の有無や DDL/DML のサポートは「エンジンの実装」と「互換性レベルによる既定挙動」の交差で決まります。Azure SQL Database のエンジンは常に最新なので、互換性レベルを上げるだけで恩恵を最大化できるケースが多いと覚えておくと良いでしょう。
互換性レベルの確認と変更(最短手順)
現在値の確認
SELECT name, compatibility_level
FROM sys.databases
WHERE name = N'YourDBName';
変更(例:SQL Server 2022 相当の 160 へ)
ALTER DATABASE [YourDBName]
SET COMPATIBILITY_LEVEL = 160; -- 160 = SQL Server 2022 相当
この操作はオンラインで即時反映されます(接続中のセッションはトランザクション境界に応じて影響を受け得るため、事前の周知と安全時間帯での実施を推奨します)。
SSMS / Azure Data Studio / ポータルで実施する場合
- SSMS:対象 DB のプロパティ → Options → Compatibility level を変更 → OK。
- Azure Data Studio:接続後、クエリエディタで上記の
ALTER DATABASE ...を実行。 - Azure ポータル:DB 画面 → クエリエディタ に入り、同じく SQL を実行。
ロールバックの即応スクリプト
互換性レベルを上げた直後にレイテンシが悪化した場合は、速やかに元の値へ戻せます。
-- 例:以前の値が 150 だった場合
ALTER DATABASE [YourDBName]
SET COMPATIBILITY_LEVEL = 150;
Sequelize の「12.0 は非対応」警告はどう見るべきか
発生のメカニズム
Sequelize(mssql 方言)は内部で @@VERSION や SERVERPROPERTY('ProductVersion') を参照し、文字列からメジャーバージョンを推定しています。Azure SQL Database は仕様上「12.x」を返すため、“14 以上に更新してください”という 誤判定の警告が出ます。
結論:クラウド版 Azure SQL では無視してよい
- エンジンは常に最新で、セキュリティ修正・最適化も自動反映されます。
- 互換性レベルを上げれば 2019/2022 世代の最適化が有効になります。
- よって、「12.x 表示=古くて危険」ではないため、警告は無害です。
CI/CD で警告を抑止する実装例(Node.js)
ビルド時に「警告=失敗」としている場合、ログ関数でフィルタすれば実害を回避できます。
import { Sequelize } from 'sequelize';
const filteredLogger = (msg) => {
if (typeof msg === 'string' && msg.match(/(mssql).*(version).*(12\.0)/i)) {
return; // Azure SQL の誤警告を無視
}
console.log(msg);
};
const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASS, {
host: process.env.DB_HOST,
dialect: 'mssql',
logging: filteredLogger,
dialectOptions: {
options: {
encrypt: true, // Azure 既定
trustServerCertificate: false
}
}
});
// 起動時に一度だけ確認:互換性レベルをロギングしておくと安心
await sequelize.query(`
SELECT DB_NAME() AS db, compatibility_level
FROM sys.databases WHERE name = DB_NAME();
`);
アプリから見える「DB の新しさ」は互換性レベルで決まります。警告を恐れて環境を作り直す必要はありません。
互換性レベルを上げる前後での影響確認ポイント
- クエリ プランの変化:最適化モデルが切り替わるため、実行計画が変わる可能性がある(特に複雑な結合・UDF 多用・テーブル変数中心のコード)。
- Intelligent Query Processing(IQP)の有効化:互換性 150 で UDF インライン化、テーブル変数の遅延コンパイル、Rowstore へのバッチモード、互換性 160 で Parameter Sensitive Plan(PSP)など。
- Query Store:Azure SQL Database では既定で有効。プラン回帰の検知・強制(force last good plan)に活用。
- データベース スコープ構成:一部の最適化は個別フラグでも制御可能(例:
QUERY_OPTIMIZER_HOTFIXES、LEGACY_CARDINALITY_ESTIMATIONなど)。
事前診断と段階的ロールアウト手順(推奨)
- ステージングでの代表負荷テスト:本番相当のデータ量、代表クエリ、主要ジョブを再現。
- 互換性レベルを 150 → 160 と段階的に上げる:各段階で遅延や CPU/IO の傾向を観察。
- Query Store を基点に回帰クエリを洗い出し:ワースト上位をチューニング、必要ならプラン固定。
- 本番は段階適用+即ロールバック準備:対象アプリ/テナント単位で徐々に切替。
運用に役立つ T‑SQL スニペット
Query Store で回帰を検出(直近と過去の比較)
-- 直近 24 時間と、その直前 24 時間で CPU 時間が悪化したクエリ上位
WITH
intervals AS (
SELECT TOP (2) runtime_stats_interval_id
FROM sys.query_store_runtime_stats_interval
ORDER BY end_time DESC
),
curr AS (
SELECT q.query_id, SUM(rs.avg_cpu_time * rs.count_executions) AS cpu
FROM sys.query_store_query q
JOIN sys.query_store_plan p ON p.query_id = q.query_id
JOIN sys.query_store_runtime_stats rs ON rs.plan_id = p.plan_id
WHERE rs.runtime_stats_interval_id = (SELECT MIN(runtime_stats_interval_id) FROM intervals)
GROUP BY q.query_id
),
prev AS (
SELECT q.query_id, SUM(rs.avg_cpu_time * rs.count_executions) AS cpu
FROM sys.query_store_query q
JOIN sys.query_store_plan p ON p.query_id = q.query_id
JOIN sys.query_store_runtime_stats rs ON rs.plan_id = p.plan_id
WHERE rs.runtime_stats_interval_id = (SELECT MAX(runtime_stats_interval_id) FROM intervals)
GROUP BY q.query_id
)
SELECT TOP (20)
qsq.query_id,
ISNULL(prev.cpu,0) AS cpu_prev,
ISNULL(curr.cpu,0) AS cpu_curr,
(ISNULL(curr.cpu,0) - ISNULL(prev.cpu,0)) AS cpu_delta
FROM curr
FULL JOIN prev ON curr.query_id = prev.query_id
JOIN sys.query_store_query qsq ON qsq.query_id = ISNULL(curr.query_id, prev.query_id)
ORDER BY cpu_delta DESC;
現在の互換性レベルとスコープ構成を一覧
SELECT DB_NAME() AS db, compatibility_level
FROM sys.databases WHERE name = DB_NAME();
SELECT name, value, is_value_default
FROM sys.database_scoped_configurations
ORDER BY name;
問題発生時に個別に旧来挙動へ寄せる(例)
-- 例:レガシー CE を一時的に有効化
ALTER DATABASE SCOPED CONFIGURATION SET LEGACY_CARDINALITY_ESTIMATION = ON;
-- 例:Query Optimizer Hotfix 群をまとめて有効化(Trace Flag 4199 相当)
ALTER DATABASE SCOPED CONFIGURATION SET QUERY_OPTIMIZER_HOTFIXES = ON;
互換性レベル別:注目の最適化・機能ハイライト
| 互換性 | 最適化・機能 | 効果・ねらい |
|---|---|---|
| 150 | Scalar UDF のインライン化 | UDF 呼び出しのループ化による遅さを解消。大量行の処理が高速化。 |
| 150 | テーブル変数の遅延コンパイル | 実行時の行数を推定に反映し、過小見積り起因のプラン劣化を抑制。 |
| 150 | Rowstore へのバッチモード | 列指向なしでも一部クエリでバッチモードの並列最適化が適用。 |
| 160 | Parameter Sensitive Plan (PSP) | パラメーターの分布差に応じて複数プランを保持し、スニッフィングの負面を緩和。 |
これらは「エンジンが新しいから使える」のではなく、互換性レベルを上げることで“既定で有効”になる点が肝です。アプリの性能課題がこれらと親和性が高ければ、互換性 150/160 への更新が最小コストの性能改善になります。
サービス層(General Purpose / Business Critical / Hyperscale)と“バージョン”は別物
DTU/vCore、General Purpose/Business Critical/Hyperscale、読み取りスケールやゾーン冗長といったサービス層の選択は性能・可用性の話であり、エンジンのバージョンとは無関係です。CPU・IO・ストレージ要件に応じてスケールや層を選びつつ、T‑SQL の挙動は互換性レベルで制御します。両者は補完関係にあります。
典型シナリオ別の実践ガイド
① 新規開発(Sequelize + Azure SQL Database)
- 最初から 互換性 160 を前提に設計(PSP 等を活かす)。
- Sequelize の警告はログでフィルタし、品質ゲートの妨げにしない。
- Query Store をダッシュボードに組み込み、回帰の自動検知を行う。
② 既存アプリ移行(オンプレ → Azure SQL Database)
- 移行直後は現行と同じ互換性レベルに合わせて安全に動作させる。
- ステージングで 150 → 160 へ段階更新、性能差と機能差を確認。
- 本番は段階適用とし、問題が出るモジュールは スコープ構成で一時的に旧挙動に寄せる。
③ 性能問題の改善を狙いたい
- まずは 互換性 150 を検討(UDF とテーブル変数に効きやすい)。
- パラメータ分布の偏りが強い OLTP では 互換性 160 の PSP が効く可能性大。
- Query Store ヒントや
FORCE LAST GOOD PLANを組み合わせ、段階的に最適化。
“安全に上げる”ためのチェックリスト
- 代表クエリの 実行計画を保存(ベースライン)。
- Query Store のキャプチャが有効であることを確認。
- 互換性レベル変更の直後は CPU / IO / 待機統計を重点監視。
- 悪化クエリは プラン固定 or スコープ構成で一時対応。
- 必要に応じて旧レベルに 即ロールバックできる手順を台本化。
FAQ
Q. 「12.x」を「16.x(v16)」へ変更できますか?
A. できません。Azure では v12 系の表記が仕様です。代わりに互換性レベルを 160へ設定します。
Q. 互換性レベルを上げても使えない機能があります。
A. 一部の機能はサービス層や権限、あるいはエンジン側の段階ロールアウト状況に依存します。互換性レベルは最適化と既定挙動の切替が主目的だと捉えてください。
Q. Azure SQL Managed Instance(MI)や SQL Server on VM との違いは?
A. MI や VM は「インスタンス機能」が豊富(SQL Agent 等)。ただし本記事の論点(“12.x 表示”問題と互換性レベルの考え方)は Azure SQL Database 固有の挙動を前提にしています。
Q. Sequelize の警告を完全になくす方法はありますか?
A. 既定では Azure の仕様上困難です。アプリ側でログをフィルタするか、ライブラリの更新を待つアプローチになります。警告自体は無害です。
トラブル発生時のセルフチェック(短時間で原因切り分け)
- 変更前後の互換性レベルを再確認(誤操作がないか)。
- トップの重いクエリを Query Store で比較(直近 vs 過去)。
- 該当クエリに UDF/テーブル変数/パラメータ偏りがないかを確認。
- 一時的に LEGACY_CARDINALITY_ESTIMATION を ON へ(緩和確認)。
- 効果が薄い場合は 元の互換性へ即戻して再計画。
実運用テンプレート:互換性レベル更新の台本
-- ① ベースライン取得
SELECT GETUTCDATE() AS collected_at, * INTO dbo.baseline_plans
FROM sys.query_store_plan;
-- ② 互換性レベルを 160 へ
ALTER DATABASE [YourDBName] SET COMPATIBILITY_LEVEL = 160;
-- ③ 監視(簡易)
SELECT TOP (50) qsqt.query_sql_text, rs.avg_duration, rs.avg_cpu_time, rs.count_executions
FROM sys.query_store_query_text qsqt
JOIN sys.query_store_query qsq ON qsq.query_text_id = qsqt.query_text_id
JOIN sys.query_store_plan qsp ON qsp.query_id = qsq.query_id
JOIN sys.query_store_runtime_stats rs ON rs.plan_id = qsp.plan_id
ORDER BY rs.avg_duration DESC;
-- ④ 回帰が出たクエリはプラン固定(例)
-- EXEC sp_query_store_force_plan @query_id = 123, @plan_id = 456;
キーメッセージ(まとめ)
- Azure SQL Database の「12.x」表示は仕様であり、古い=危険ではありません。エンジンは常に最新。
- アプリが求めるのは 互換性レベルの設定です。160(SQL Server 2022 相当)を起点に検討しましょう。
- Sequelize の「12.0 は非対応」警告は 誤判定で、無視して問題ありません(必要ならログで抑止)。
- 更新は 段階適用+Query Store 監視+即ロールバック手順の三点セットで安全に。
- 性能改善を狙うなら、150/160 の IQP 世代を活かすのが最小コストの勝ち筋です。
付録:実務 FAQ ミニカタログ
| 質問 | 要点回答 | 備考 |
|---|---|---|
| バージョン指定欄が見当たらない | オンプレのようなメジャー選択は不可。互換性レベルだけを調整する。 | SSMS/ポータル/クエリで変更。 |
| Sequelize が 14 以上を要求 | Azure は常に 12.x を返すため誤警告。無視 or ログ抑止。 | 品質ゲートのルールから除外。 |
| 最新機能を使いたい | 多くはエンジン側で利用可。互換性 160で最適化が“既定で有効”。 | 一部は挙動フラグや権限に依存。 |
| 性能が悪化した | Query Storeで回帰を特定、プラン固定や スコープ構成で緩和。 | 必要なら旧レベルへロールバック。 |
| サービス層を上げれば解決? | スループットは伸びるが、最適化の賢さは互換性レベルに依存。 | 両輪で最適化。 |
実践のコア:この 3 行だけ覚えれば十分
-- 1) 今の互換性を知る
SELECT name, compatibility_level FROM sys.databases WHERE name = DB_NAME();
-- 2) 2022 相当へ“更新”
ALTER DATABASE [YourDBName] SET COMPATIBILITY_LEVEL = 160;
-- 3) 変化を見張る(Query Store)
SELECT TOP 10 * FROM sys.query_store_runtime_stats ORDER BY last_execution_time DESC;
これが、Azure SQL Database の「バージョンを上げたい」問題の最短解です。メジャーバージョンではなく互換性レベルを操作し、Query Store を味方につけて一歩ずつ前進しましょう。

コメント