производительность оператора isnull против оператора select case

#sql #sql-server #tsql #sql-server-2012 #dynamics-crm-2013

#sql #sql-сервер #tsql #sql-server-2012 #динамика-crm-2013

Вопрос:

Что быстрее?

 update c
set 
c.createdon=q.CreatedOn 
,c.createdby=case when q.createdby is not null then q.createdby end
,c.modifiedon=q.modifiedon 
,c.modifiedby=case when q.ModifiedBy is not null then q.ModifiedBy end
from crm_annotationbase c
join IncidentWorknote q
on c.annotationid=q.annotationid
  

или это:

 update c
set 
c.createdon=q.CreatedOn 
,c.createdby=isnull(q.createdby,c.createdby) 
,c.modifiedon=q.modifiedon 
,c.modifiedby=isnull(q.modifiedby,c.modifiedby)
from crm_annotationbase c
join IncidentWorknote q
on c.annotationid=q.annotationid
  

У меня первый запрос выполняется уже 24 часа. Я обновляю таблицу CRM 2013 на основе промежуточных данных.

Я хотел бы знать, выбрал ли я наиболее эффективное решение для этого?

Комментарии:

1. Если вы хотите оптимизировать 24-часовой запрос для выполнения значительно быстрее, проверка null — это последнее, на что я бы обратил внимание. На самом деле это просто выбор произвольного элемента этого запроса и обвинение его в проблемах с производительностью.

2. В этой статье подробно описывается производительность между COALESCE и ISNULL. ОБЪЕДИНЕНИЕ — это, по сути, скрытый СЛУЧАЙ. sqlmag.com/t-sql/coalesce-vs-isnull

3. Согласитесь с приведенными выше утверждениями, почему бы не ускорить его, выполнив where q.modifiedon >= GetDate() -1

4. Вы постоянно обновляете все записи, вам нужно обновлять только те, которые были изменены. Я предположил, что вы запускаете его ежедневно. Вы можете относительно легко ограничить обновляемые записи.

5. @MikeMiller большое спасибо. но я не знаю, как определить, изменилась ли запись. мне нужно запустить этот процесс только один раз.

Ответ №1:

Хорошо .. Мне пришлось покопаться в этом скрипте. Судя по комментариям, это очень большая таблица, которую вы пытаетесь обновить. ЛУЧШИЙ способ ускорить это обновление — разбить его на пакеты. Причина, по которой это занимает так много времени, заключается в транзакционном характере системы… Если что-то не удается, ВСЯ транзакция (все ваше обновление) будет отменена. Это занимает ОООЧЕНЬ много дополнительного времени. Если вам НЕ нужна эта транзакционная схема «все или ничего», попробуйте что-то вроде этого (ниже). Нам нужно обновить сотни миллионов записей, и мы смогли ускорить это на НЕСКОЛЬКО ЧАСОВ, просто выполнив пакетное обновление.

Настройка этого может ускорить работу на основе ваших данных.

 DECLARE @Update INT
                DECLARE @Batch INT

                -- Total number of records in database
                SELECT @Update = (
                    SELECT COUNT(id)
                    FROM [table] WITH (NOLOCK) -- be CAREFUL with this
                    WHERE ['   @fName   '] IS NOT NULL) --optional

                SELECT @Batch = 4000 --Batch update amount

                WHILE (@Update > 0)
                    BEGIN

                    UPDATE TOP(@Batch) c
                    set 
                    c.createdon=q.CreatedOn 
                    ,c.createdby=case when q.createdby is not null then q.createdby end
                    ,c.modifiedon=q.modifiedon 
                    ,c.modifiedby=case when q.ModifiedBy is not null then q.ModifiedBy end
                    from crm_annotationbase c
                    join IncidentWorknote q
                    on c.annotationid=q.annotationid

                    SELECT @Update = @Update - @Batch; -- Reduce for next set

                    WAITFOR DELAY '000:00:00.400'; -- Allows for waiting transactions to process optional
                    END;
  

Комментарии:

1. Кроме того, это было бы быстрее, если бы annotationId был первичным ключом. Вы могли бы добавить оператор where типа «Где annotationId находится между @minBatch и @maxBatch» или что-то в этом роде. 🙂

2. Да.. Это то, что сработало для нас быстрее всего. Вы могли бы попробовать запустить его в более высоких пакетах. Но убедитесь, что логика верна перед запуском в производство (очевидно). TOP сработал для нас, потому что я ограничиваю обновление с помощью оператора WHERE, чтобы при обновлении четырех тысяч записей они больше не были в ВЕРХНЕЙ группе (потому что условие не выполняется).

Ответ №2:

То, что вы делаете, неправильно по двум причинам:

  1. Прямое обновление базы данных Dynamics CRM не поддерживается и может привести к ряду проблем с вашим экземпляром CRM (для обновления данных необходимо использовать веб-службы CRM)
  2. CreatedOn , CreatedBy , ModifiedOn и ModifiedBy являются системными полями, и они всегда заполняются, они никогда не содержат нулевых значений. (в частности CreatedOn , и CreatedBy указываются при создании записи и не могут быть изменены после, ModifiedOn и ModifiedBy обновляются при каждом обновлении записи)

Как советует Microsoft здесь: http://msdn.microsoft.com/en-us/library/gg328350.aspx#Unsupported

Неподдерживаемые настройки

Изменения данных (записи) в базе данных Microsoft Dynamics CRM с использованием команд SQL или любой технологии, отличной от описанной в Microsoft Dynamics CRM SDK.

Комментарии:

1. 1. пожалуйста, покажите мне источник, в котором говорится, что эти конкретные поля опасно обновлять вручную. я говорил об этом с MVP CRM, и он сказал, что все в порядке.

2. 2. правильно, но я проверяю наличие нулевых значений в промежуточной базе данных, а не в crm

3. вы обновляете базу данных CRM или нет? Я не могу поверить, что MVP CRM сказал, что это нормально для непосредственного обновления базы данных CRM.