在SQL Server中使用游标的更快替代方法

时间:2019-04-01 14:12:55

标签: sql-server tsql database-cursor

我有一个游标,它遍历数据库中的每个基本表。它通过执行一条动态SQL将记录插入到另一个表中,但是到目前为止,它需要花费20分钟以上的时间来执行。

DECLARE TableCursor CURSOR FOR
    SELECT TABLE_NAME
    FROM <DB>.INFORMATION_SCHEMA.TABLES
    WHERE TABLE_TYPE = 'BASE TABLE'

WHILE(@@FETCH_STATUS = 0)
BEGIN
    #Dynamic SQL Query to insert data into each table in cursor#

我进行了一些研究,发现使用带有UNION表达式的CTE会更快,但是我不确定如何进行转换,例如如何遍历CTE中的每个表。

非常感谢您的帮助。

编辑:这是动态SQL的示例:

SELECT @SQL = 'WITH CTE_DATES(DATE_VAL) AS (
    SELECT DISTINCT DATE_VAL
    FROM DATE_EVERY_DAY
    WHERE DATE_VAL <= GETDATE()
)
INSERT INTO COUNT_RECORDS_TABLE (DATE_VAL, TABLE_NAME, NUM_RECS_IMPORTED)
SELECT cd.DATE_VAL, ''' + @TableName + ''' AS TABLE_NAME, COUNT(CAST(tn.IMPORT_DATE AS DATE)) AS NUM_RECS_IMPORTED
FROM CTE_DATES AS cd LEFT JOIN ' + @TableName + ' AS tn 
ON CAST(tn.IMPORT_DATE AS DATE) = cd.DATE_VAL
GROUP BY cd.DATE_VAL'

1 个答案:

答案 0 :(得分:1)

我会尝试使用sys.sp_MSForeachTable。这大约是最快的速度,而?字符是[schema]。[tablename]格式的表名。很明显,如果您只需要表名,则可以做一些文本替换。直接替换意味着您无需弄乱CTE,并且如果DATE_EVERY_DAY.DATE_VAL列上有索引,则该查询可以利用它。

EXEC sys.sp_MSforeachtable 
'INSERT INTO COUNT_RECORDS_TABLE (DATE_VAL, TABLE_NAME, NUM_RECS_IMPORED)
SELECT 
    cd.DATE_VAL,
    ''?'' AS TABLE_NAME, 
    COUNT(tn.IMPORT_DATE) AS NUM_RECS_IMPORTED 
FROM 
    DATE_EVERY_DAY AS cd
    LEFT JOIN 
    ? AS tn ON 
        CAST(tn.IMPORT_DATE AS DATE)=cd.DATE_VAL
WHERE
    DATE_VAL <= GETDATE()
GROUP BY
    cd.DATE_VAL
'

这里有一个深入的示例:SQL Server Undocumented Stored Procedures sp_MSforeachtable and sp_MSforeachdb