Desde mi perspectiva, su servidor tiene un grave problema de rendimiento. Incluso si asumimos que ninguno de los registros en la consulta
select some_col with (nolock) where id_col between 57000000 and 57001000
estaba en la memoria, no debería tomar 21 segundos leer las pocas páginas secuencialmente desde el disco (su índice agrupado en id_col no debería estar fragmentado si es una identidad automática y no hizo algo estúpido como agregar un "desc" a la definición del índice).
Pero si no puede/no quiere arreglar eso, mi consejo sería hacer la actualización en paquetes pequeños como 100-1000 registros a la vez (dependiendo de cuánto tiempo consuma la función de búsqueda). Una actualización/transacción no debería tomar más de 30 segundos.
Verá que cada actualización mantiene un bloqueo exclusivo en todos los registros que modificó hasta que se complete la transacción. Si no usa una transacción explícita, cada declaración se ejecuta en un solo contexto de transacción automática, por lo que los bloqueos se liberan cuando se realiza la declaración de actualización.
Pero aún puede encontrarse con puntos muertos de esa manera, dependiendo de lo que hagan los otros procesos. Si también modifican más de un registro a la vez, o incluso si recopilan y retienen bloqueos de lectura en varias filas, puede generar interbloqueos.
Para evitar los interbloqueos, su declaración de actualización debe bloquear todos los registros que modificará a la vez. La forma de hacer esto es colocar la declaración de actualización única (con solo unas pocas filas limitadas por id_col) en una transacción serializable como
IF @@TRANCOUNT > 0
-- Error: You are in a transaction context already
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
-- Insert Loop here to work "x" through the id range
BEGIN TRANSACTION
UPDATE SOMETABLE
SET [some_col] = dbo.ufn_SomeFunction(CONVERT(NVARCHAR(500), another_column))
WHERE [some_col] = 243 AND id_col BETWEEN x AND x+500 -- or whatever keeps the update in the small timerange
COMMIT
-- Next loop
-- Get all new records while you where running the loop. If these are too many you may have to paginate this also:
BEGIN TRANSACTION
UPDATE SOMETABLE
SET [some_col] = dbo.ufn_SomeFunction(CONVERT(NVARCHAR(500), another_column))
WHERE [some_col] = 243 AND id_col >= x
COMMIT
Para cada actualización, esto requerirá un bloqueo de rango de clave de actualización/exclusivo en los registros dados (pero solo en ellos, porque limita la actualización a través de la clave de índice agrupado). Esperará a que finalice cualquier otra actualización en los mismos registros, luego obtendrá su bloqueo (lo que provocará el bloqueo de todas las demás transacciones, pero solo para los registros dados), luego actualizará los registros y liberará el bloqueo.
La última declaración adicional es importante, porque tomará un bloqueo de rango de teclas hasta "infinito" y, por lo tanto, evitará incluso las inserciones al final del rango mientras se ejecuta la declaración de actualización.