データベース
Microsoft SQL Server
概要
Microsoft SQL Serverは、マイクロソフトが開発・提供する企業向けリレーショナルデータベース管理システムです。Windows環境との高い親和性、強力な統合開発環境、包括的なビジネスインテリジェンス機能を特徴とし、中小企業から大企業まで幅広く利用されています。
詳細
SQL Serverは1989年に初版がリリースされ、継続的な進化により現在では以下の特徴を持つ統合データプラットフォームとなっています。
主要特徴
- Always On Availability Groups: 高可用性とディザスタリカバリ
- In-Memory Technologies: In-Memory OLTP(Hekaton)と列ストアインデックス
- Intelligent Query Processing: AI駆動のクエリ最適化
- Azure Integration: ハイブリッドクラウド機能とAzure SQL Database
- Stretch Database: ホットとコールドデータの自動階層化
- PolyBase: 外部データソースとの統合
- JSON Support: ネイティブJSONサポート
- R and Python Integration: 高度な分析とML機能
- Graph Database: グラフデータモデルのサポート
エディション
- Express: 軽量で無料の開発用エディション(10GB制限)
- Standard: 中小企業向け標準機能版
- Enterprise: エンタープライズ向け全機能版
- Developer: 開発者向け無料版(Enterprise機能付き)
- Web: Web アプリケーション向け
- Azure SQL Database: フルマネージドクラウド版
統合コンポーネント
- SQL Server Reporting Services (SSRS): レポート作成・配布
- SQL Server Integration Services (SSIS): ETL/データ統合
- SQL Server Analysis Services (SSAS): OLAP・データマイニング
- SQL Server Master Data Services (MDS): マスターデータ管理
メリット・デメリット
メリット
- Windows統合: Active Directory認証、Windows Services統合
- 豊富な開発ツール: SQL Server Management Studio (SSMS)、Visual Studio統合
- 包括的なBI機能: SSRS、SSIS、SSAS による完全なBI ソリューション
- 高い可用性: Always On、フェイルオーバークラスタリング
- Azure統合: シームレスなクラウド移行とハイブリッド構成
- 強力なセキュリティ: 行レベルセキュリティ、動的データマスキング
- 優秀なパフォーマンス: In-Memory技術と自動チューニング
- Microsoft サポート: 包括的な技術サポートとドキュメント
デメリット
- Windows依存: LinuxサポートはあるがWindows中心の設計
- ライセンスコスト: コア単位の高額なライセンス体系
- リソース消費: 大量のメモリとCPUを必要とする
- ベンダーロックイン: Microsoft テクノロジーエコシステムへの依存
- 学習コスト: T-SQL固有の機能習得が必要
- 仮想化制限: 一部エディションで仮想化制約
主要リンク
書き方の例
インストール・セットアップ
# SQL Server 2022 Expressのダウンロードとインストール
# https://www.microsoft.com/sql-server/sql-server-downloads
# サイレントインストール例
.\SQLEXPR_x64_JPN.exe /ACTION=Install /FEATURES=SQL /INSTANCENAME=SQLEXPRESS /SECURITYMODE=SQL /SAPWD="StrongPassword123!" /IAcceptSQLServerLicenseTerms
# Docker Linuxコンテナ
docker pull mcr.microsoft.com/mssql/server:2022-latest
docker run -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=StrongPassword123!" \
-p 1433:1433 --name sql-server \
mcr.microsoft.com/mssql/server:2022-latest
# サービス確認
Get-Service MSSQLSERVER
net start MSSQLSERVER
# SQL Server Configuration Manager
# Services → SQL Server (MSSQLSERVER) → Properties
基本操作(CRUD)
-- データベース作成
CREATE DATABASE CompanyDB
ON (
NAME = 'CompanyDB',
FILENAME = 'C:\Data\CompanyDB.mdf',
SIZE = 100MB,
MAXSIZE = 1GB,
FILEGROWTH = 10MB
)
LOG ON (
NAME = 'CompanyDB_Log',
FILENAME = 'C:\Data\CompanyDB.ldf',
SIZE = 10MB,
FILEGROWTH = 10%
);
USE CompanyDB;
-- テーブル作成
CREATE TABLE Employees (
EmployeeID INT IDENTITY(1,1) PRIMARY KEY,
FirstName NVARCHAR(50) NOT NULL,
LastName NVARCHAR(50) NOT NULL,
Email NVARCHAR(100) UNIQUE,
HireDate DATETIME2 DEFAULT GETDATE(),
Salary DECIMAL(10,2),
DepartmentID INT,
IsActive BIT DEFAULT 1
);
-- データ挿入
INSERT INTO Employees (FirstName, LastName, Email, Salary, DepartmentID)
VALUES
(N'太郎', N'田中', '[email protected]', 75000.00, 1),
(N'花子', N'佐藤', '[email protected]', 65000.00, 2);
-- データ選択
SELECT
EmployeeID,
FirstName + ' ' + LastName AS FullName,
Email,
FORMAT(HireDate, 'yyyy/MM/dd') AS HireDateFormatted,
FORMAT(Salary, 'C', 'ja-JP') AS SalaryFormatted
FROM Employees
WHERE IsActive = 1;
-- データ更新
UPDATE Employees
SET Salary = Salary * 1.1
WHERE HireDate < DATEADD(YEAR, -1, GETDATE());
-- データ削除(論理削除)
UPDATE Employees SET IsActive = 0 WHERE EmployeeID = 2;
データモデリング
-- 外部キー制約付きテーブル設計
CREATE TABLE Departments (
DepartmentID INT IDENTITY(1,1) PRIMARY KEY,
DepartmentName NVARCHAR(100) NOT NULL,
ManagerID INT,
Budget MONEY DEFAULT 0
);
ALTER TABLE Employees
ADD CONSTRAINT FK_Employees_Department
FOREIGN KEY (DepartmentID) REFERENCES Departments(DepartmentID);
-- JSON列の使用
CREATE TABLE CustomerProfiles (
CustomerID INT IDENTITY(1,1) PRIMARY KEY,
CustomerName NVARCHAR(100),
ProfileData NVARCHAR(MAX) CHECK (ISJSON(ProfileData) = 1),
Preferences NVARCHAR(MAX) CHECK (ISJSON(Preferences) = 1)
);
INSERT INTO CustomerProfiles (CustomerName, ProfileData, Preferences)
VALUES (
N'田中太郎',
N'{"age": 30, "city": "Tokyo", "skills": ["C#", "SQL Server"]}',
N'{"newsletter": true, "language": "ja"}'
);
-- 計算列とインデックス
ALTER TABLE CustomerProfiles
ADD Age AS JSON_VALUE(ProfileData, '$.age');
CREATE INDEX IX_CustomerProfiles_Age ON CustomerProfiles(Age);
-- テンポラルテーブル(履歴管理)
CREATE TABLE Products (
ProductID INT IDENTITY(1,1) PRIMARY KEY,
ProductName NVARCHAR(100) NOT NULL,
Price MONEY,
SysStartTime DATETIME2 GENERATED ALWAYS AS ROW START,
SysEndTime DATETIME2 GENERATED ALWAYS AS ROW END,
PERIOD FOR SYSTEM_TIME (SysStartTime, SysEndTime)
) WITH (SYSTEM_VERSIONING = ON);
インデックス・最適化
-- インデックス作成
CREATE NONCLUSTERED INDEX IX_Employees_Department
ON Employees(DepartmentID) INCLUDE (FirstName, LastName);
CREATE NONCLUSTERED INDEX IX_Employees_Email
ON Employees(Email) WHERE IsActive = 1;
-- カラムストアインデックス
CREATE NONCLUSTERED COLUMNSTORE INDEX IX_Sales_Columnstore
ON Sales (ProductID, CustomerID, SaleDate, Amount);
-- フルテキストインデックス
CREATE FULLTEXT CATALOG EmployeeFullTextCatalog;
CREATE FULLTEXT INDEX ON Employees(FirstName, LastName)
KEY INDEX PK__Employee__7AD04F11A11A1A1A
ON EmployeeFullTextCatalog;
SELECT * FROM Employees
WHERE CONTAINS((FirstName, LastName), '"田中*"');
-- 実行プラン分析
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
-- 実際の実行プランを表示
SET SHOWPLAN_ALL ON;
SELECT * FROM Employees WHERE DepartmentID = 1;
SET SHOWPLAN_ALL OFF;
-- インデックス使用状況
SELECT
t.name AS TableName,
i.name AS IndexName,
s.user_seeks, s.user_scans, s.user_lookups,
s.user_updates
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.object_id = i.object_id AND s.index_id = i.index_id
INNER JOIN sys.tables t ON i.object_id = t.object_id;
実用例
-- ストアドプロシージャ(T-SQL)
CREATE PROCEDURE sp_CalculateBonus
@DepartmentID INT,
@BonusRate DECIMAL(5,4) = 0.10
AS
BEGIN
SET NOCOUNT ON;
DECLARE @TotalBonus MONEY = 0;
UPDATE Employees
SET Bonus = Salary * @BonusRate
WHERE DepartmentID = @DepartmentID AND IsActive = 1;
SELECT @TotalBonus = SUM(Bonus)
FROM Employees
WHERE DepartmentID = @DepartmentID AND IsActive = 1;
PRINT 'Total bonus allocated: ' + FORMAT(@TotalBonus, 'C', 'ja-JP');
SELECT
EmployeeID,
FirstName + ' ' + LastName AS FullName,
FORMAT(Salary, 'C', 'ja-JP') AS Salary,
FORMAT(Bonus, 'C', 'ja-JP') AS Bonus
FROM Employees
WHERE DepartmentID = @DepartmentID AND IsActive = 1;
END;
EXEC sp_CalculateBonus @DepartmentID = 1, @BonusRate = 0.15;
-- ユーザー定義関数
CREATE FUNCTION dbo.GetEmployeeAge(@BirthDate DATE)
RETURNS INT
AS
BEGIN
RETURN DATEDIFF(YEAR, @BirthDate, GETDATE()) -
CASE WHEN DATEADD(YEAR, DATEDIFF(YEAR, @BirthDate, GETDATE()), @BirthDate) > GETDATE()
THEN 1 ELSE 0 END;
END;
-- トリガー
CREATE TRIGGER tr_EmployeeAudit
ON Employees
AFTER UPDATE
AS
BEGIN
INSERT INTO EmployeeAudit (
EmployeeID, ChangeDate, OldSalary, NewSalary, ChangedBy
)
SELECT
i.EmployeeID,
GETDATE(),
d.Salary,
i.Salary,
SUSER_SNAME()
FROM inserted i
INNER JOIN deleted d ON i.EmployeeID = d.EmployeeID
WHERE i.Salary <> d.Salary;
END;
-- Common Table Expression (CTE)
WITH DepartmentStats AS (
SELECT
d.DepartmentName,
COUNT(e.EmployeeID) AS EmployeeCount,
AVG(e.Salary) AS AvgSalary,
MAX(e.Salary) AS MaxSalary
FROM Departments d
LEFT JOIN Employees e ON d.DepartmentID = e.DepartmentID
WHERE e.IsActive = 1
GROUP BY d.DepartmentID, d.DepartmentName
)
SELECT * FROM DepartmentStats
WHERE EmployeeCount > 0
ORDER BY AvgSalary DESC;
ベストプラクティス
-- セキュリティ設定
-- 行レベルセキュリティ
CREATE FUNCTION dbo.fn_securitypredicate(@DepartmentID INT)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT 1 AS fn_securitypredicate_result
WHERE @DepartmentID = CAST(SESSION_CONTEXT(N'DepartmentID') AS INT);
CREATE SECURITY POLICY DepartmentSecurityPolicy
ADD FILTER PREDICATE dbo.fn_securitypredicate(DepartmentID) ON dbo.Employees
WITH (STATE = ON);
-- 動的データマスキング
ALTER TABLE Employees
ALTER COLUMN Email ADD MASKED WITH (FUNCTION = 'email()');
-- 透明なデータ暗号化 (TDE)
CREATE DATABASE ENCRYPTION KEY
WITH ALGORITHM = AES_256
ENCRYPTION BY SERVER CERTIFICATE TDECert;
ALTER DATABASE CompanyDB SET ENCRYPTION ON;
-- バックアップとリストア
-- 完全バックアップ
BACKUP DATABASE CompanyDB
TO DISK = 'C:\Backups\CompanyDB_Full.bak'
WITH FORMAT,
NAME = 'CompanyDB Full Backup',
DESCRIPTION = 'Full backup of CompanyDB';
-- トランザクションログバックアップ
BACKUP LOG CompanyDB
TO DISK = 'C:\Backups\CompanyDB_Log.trn';
-- リストア
RESTORE DATABASE CompanyDB_Test
FROM DISK = 'C:\Backups\CompanyDB_Full.bak'
WITH MOVE 'CompanyDB' TO 'C:\Data\CompanyDB_Test.mdf',
MOVE 'CompanyDB_Log' TO 'C:\Data\CompanyDB_Test.ldf',
REPLACE;
-- Always On 可用性グループ
-- (事前にWindows Server Failover Clustering設定が必要)
CREATE AVAILABILITY GROUP AG_CompanyDB
WITH (AUTOMATED_BACKUP_PREFERENCE = SECONDARY)
FOR DATABASE CompanyDB
REPLICA ON
N'SQL-NODE1' WITH (ENDPOINT_URL = N'TCP://SQL-NODE1:5022',
AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
FAILOVER_MODE = AUTOMATIC),
N'SQL-NODE2' WITH (ENDPOINT_URL = N'TCP://SQL-NODE2:5022',
AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
FAILOVER_MODE = AUTOMATIC);
-- 監視とメンテナンス
-- インデックス断片化チェック
SELECT
OBJECT_NAME(ips.object_id) AS TableName,
i.name AS IndexName,
ips.avg_fragmentation_in_percent,
ips.page_count
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'DETAILED') ips
INNER JOIN sys.indexes i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
WHERE ips.avg_fragmentation_in_percent > 30;
-- 統計情報の更新
UPDATE STATISTICS Employees WITH FULLSCAN;