sql-server について
SQL Server を扱う開発者向けの T-SQL クイックリファレンススキルです。テーブル、インデックス、ストアドプロシージャ、性能分析、問題調査の例を提供します。
主な機能
- 01T-SQL のテーブルとスキーマ例
- 02クラスター化・非クラスター化インデックス
- 03ストアドプロシージャの例
- 04クエリ性能分析
- 05SQL のアンチパターン解説
活用シーン
- 01SQL Server のテーブルとインデックス作成
- 02遅いクエリの実行状況の確認
- 03インジェクションやロック問題の回避
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ claude-dev-suite/ claude-dev-suite --skill sql-serverインストール後、Claude Code で/sql-serverを入力して読み込まれたか確認します。
詳細
SQL Server - クイックリファレンス
深い知識: EF Core + SQL Server のパターンには、テクノロジーとして
aspnet-coreを指定し、mcp__documentation__fetch_docsを使用してください。
よく使われる T-SQL パターン
-- Table creation
CREATE TABLE Users (
Id INT IDENTITY(1,1) PRIMARY KEY,
Name NVARCHAR(100) NOT NULL,
Email NVARCHAR(255) NOT NULL UNIQUE,
CreatedAt DATETIME2 DEFAULT GETUTCDATE(),
UpdatedAt DATETIME2 NULL,
IsActive BIT DEFAULT 1
);
-- Pagination (SQL Server 2012+)
SELECT * FROM Users
ORDER BY Name
OFFSET @Skip ROWS
FETCH NEXT @Take ROWS ONLY;
-- MERGE (upsert)
MERGE INTO Users AS target
USING (SELECT @Email AS Email, @Name AS Name) AS source
ON target.Email = source.Email
WHEN MATCHED THEN
UPDATE SET Name = source.Name, UpdatedAt = GETUTCDATE()
WHEN NOT MATCHED THEN
INSERT (Name, Email) VALUES (source.Name, source.Email);
-- CTE (Common Table Expression)
WITH ActiveUsers AS (
SELECT Id, Name, ROW_NUMBER() OVER (ORDER BY CreatedAt DESC) AS RowNum
FROM Users WHERE IsActive = 1
)
SELECT * FROM ActiveUsers WHERE RowNum BETWEEN 1 AND 10;
インデックス
-- Clustered (one per table, usually PK)
CREATE CLUSTERED INDEX IX_Users_Id ON Users(Id);
-- Non-clustered
CREATE NONCLUSTERED INDEX IX_Users_Email ON Users(Email);
-- Covering index (includes extra columns)
CREATE NONCLUSTERED INDEX IX_Users_Email_Include
ON Users(Email) INCLUDE (Name, CreatedAt);
-- Filtered index
CREATE NONCLUSTERED INDEX IX_Users_Active
ON Users(Email) WHERE IsActive = 1;
-- Check missing indexes
SELECT * FROM sys.dm_db_missing_index_details;
ストアドプロシージャ
CREATE PROCEDURE sp_GetUsersByStatus
@IsActive BIT,
@PageSize INT = 10,
@PageNumber INT = 1
AS
BEGIN
SET NOCOUNT ON;
SELECT Id, Name, Email, CreatedAt
FROM Users
WHERE IsActive = @IsActive
ORDER BY Name
OFFSET (@PageNumber - 1) * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY;
END;
パフォーマンスに関するヒント
| ヒント | 理由 |
|---|---|
Unicode には VARCHAR より NVARCHAR を使用する | エンコードの問題を回避できます |
| WHERE/JOIN 句の列にインデックスを追加する | クエリが高速になります |
プロシージャで SET NOCOUNT ON を使用する | ネットワークトラフィックを削減できます |
SELECT * を避ける | 必要な列だけを取得できます |
| パラメーター化クエリを使用する | SQL インジェクションを防ぎ、実行プランを再利用できます |
DATETIME より DATETIME2 を使用する | 精度が高く、ストレージ容量も少なくて済みます |
クエリパフォーマンスの分析
-- Execution plan
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
-- Run your query
SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;
-- Expensive queries
SELECT TOP 10
qs.total_elapsed_time / qs.execution_count AS avg_elapsed,
qs.execution_count,
SUBSTRING(qt.text, 1, 200) AS query_text
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
ORDER BY avg_elapsed DESC;
アンチパターン
| アンチパターン | 問題点 | 正しい方法 |
|---|---|---|
SELECT * | I/O を浪費し、スキーマ変更時に問題が発生します | 列を個別に指定します |
| 行ごとの処理にカーソルを使う | 非常に遅くなります | セットベースの操作を使用します |
| 外部キーにインデックスがない | JOIN が遅くなります | 非クラスター化インデックスを追加します |
どこでも NOLOCK を使う | ダーティリードが発生します | 適切な分離レベルを使用します |
| SQL 内で文字列を連結する | SQL インジェクションの原因になります | パラメーター化クエリを使用します |
トラブルシューティング早見表
| 問題 | 考えられる原因 | 解決策 |
|---|---|---|
| クエリが遅い | インデックスがない | 実行プランを確認します |
| デッドロック | ロックの競合 | sys.dm_tran_locks を確認します |
| タイムアウト | 実行時間の長いクエリ | 最適化するか、タイムアウトを延長します |
| 切り捨てエラー | 列のサイズが不足している | NVARCHAR の長さを確認します |
コメント
Markdown 対応