核心差異速查
| 特性 | INSERT INTO ... SELECT | SELECT ... INTO |
| 目標表 | 必須預先存在 | 自動建立 |
| 結構來源 | 目標表定義 | 查詢結果投影 |
| 權限需求 | 目標表 INSERT 權限 | 建表權限 (CREATE TABLE) |
| 索引/約束/觸發器 | 保留目標表原有 | 不複製 (僅資料+欄位定義) |
| 身分識別欄 | 需 SET IDENTITY_INSERT ON | 自動保留 IDENTITY 屬性 |
| 日誌記錄 | 完整記錄 (可最小化) | 最小日誌 (Bulk Logged/Simple 模式下) |
| 並行度 | 可指定 TABLOCK 並行 | 串行 (舊版),2014+ 支援並行 |
| 事務行為 | 可回滾 | 可回滾 (但 DDL 隱式提交風險) |
語法範例
-- INSERT INTO SELECT:目標表 t2 已存在
INSERT INTO t2 (id, name, pwd)
SELECT id, name, pwd FROM t1;
-- SELECT INTO:自動建立 t2
SELECT id, name, pwd INTO t2 FROM t1;
-- 等價於:
-- CREATE TABLE t2 (id ..., name ..., pwd ...);
-- INSERT INTO t2 SELECT id, name, pwd FROM t1;
效能與日誌深度解析
- SELECT INTO:
BULK LOGGED/SIMPLE 復原模式下最小日誌,僅記錄頁配置,速度極快,適合大量資料初始化、備份、ETL 階段表
- INSERT INTO SELECT:預設完整日誌;加
WITH (TABLOCK) + BULK LOGGED 可達最小日誌並行插入
- 大資料量 (>100 萬) 首選
SELECT INTO 建暫存表,再 INSERT INTO ... SELECT 寫正式表 (保留索引/約束)
常見陷阱
SELECT INTO 鎖定系統表 (sysobjects/syscolumns) 較久,高併發下易阻塞 → 避免核心業務高峰期執行
- 目標表有計算欄、預設值、觸發器 →
SELECT INTO 會丟失,必須用 INSERT INTO SELECT
- 身分識別欄種子值:
SELECT INTO 保留種子,INSERT INTO 需手動 DBCC CHECKIDENT 重置
最佳實踐建議
資料量 < 10 萬、需保留索引約束 → INSERT INTO SELECT
資料量 > 100 萬、臨時表/階段表、無約束 → SELECT INTO (最小日誌)
大量寫入正式表、需保留結構 →
1. SELECT INTO #stage FROM source (最小日誌、極速)
2. CREATE INDEX ON #stage ... (可選)
3. INSERT INTO target WITH (TABLOCK) SELECT ... FROM #stage (最小日誌並行)
4. DROP TABLE #stage