SQL UPDATE SET один столбец, чтобы быть равным значению в связанной таблице, на которую ссылается другой столбец?

Избегайте inline asm, когда это возможно: https://gcc.gnu.org/wiki/DontUseInlineAsm . Он блокирует множество оптимизаций. Но если вы действительно не можете удержать компилятор в создании asm, который вы хотите, вы должны, вероятно, написать весь цикл в asm, чтобы вы могли развернуть и настроить его вручную, вместо того чтобы делать такие вещи.


Вы можете использовать ограничение r для индекса. Используйте модификатор q, чтобы получить имя 64-битного регистра, чтобы вы могли использовать его в режиме адресации. Когда компилируется для 32-битных целей, модификатор q выбирает имя 32-битного регистра, поэтому тот же код все еще работает.

Если вы хотите выбрать, какой режим адресации используется, вам понадобится сделать это самостоятельно, используя операнды указателя с ограничениями r.

Синтаксис inline asm GNU C не предполагает, что вы читаете или записываете память, на которую указывают операнды указателя. (например, возможно, вы используете inline-asm and для значения указателя). Поэтому вам нужно что-то сделать с помощью "memory" clobber или операндов ввода / вывода памяти, чтобы он знал, какую память вы изменяете. "memory" clobber прост, но заставляет все, кроме локальных, проливать / перезагружать. См. Раздел Clobbers в документах для примера использования фиктивного входного операнда.


Еще одно огромное преимущество для ограничения m заключается в том, что -funroll-loops может работать путем создания адресов с постоянными смещениями. Выполнение адресации не позволяет компилятору выполнить один приращение каждые 4 итерации или что-то еще, потому что каждое значение исходного уровня i должно появиться в регистре.


Вот моя версия, с некоторые изменения, отмеченные в комментариях.

#include 
void add_asm1_memclobber(float *x, float *y, float *z, unsigned n) {
    __m128 vectmp;  // let the compiler choose a scratch register
    for(int i=0; i

Исходный компилятор Godbolt для этого и пару версий ниже.

Ваша версия должна объявить %xmm0, как сбитый, или у вас будет плохое время, когда это будет включено. Моя версия использует временную переменную как операнд только для вывода, который никогда не используется. Это дает компилятору полную свободу для размещения регистров.

Если вы хотите избежать «клонирования» памяти, вы можете использовать операнды ввода / вывода для фиктивной памяти, такие как "m" (*(const __m128*)&x[i]), чтобы сообщить компилятору , который память считывается и записывается вашей функцией. Это необходимо для обеспечения правильного генерации кода, если вы сделали что-то вроде x[4] = 1.0; прямо перед запуском этого цикла. (И даже если вы не пишете что-то, что простое, вложение и постоянное распространение могут сводиться к этому.) А также убедиться, что компилятор не читает из z[] до того, как цикл запущен.

В этом случае мы получаем ужасные результаты: gcc5.x фактически увеличивает 3 дополнительных указателя, потому что он решает использовать режимы адресации [reg] вместо индексации. Он не знает, что inline asm никогда не ссылается на эти операнды памяти, используя режим адресации, созданный с помощью ограничения!

# gcc5.4 with dummy constraints like "=m" (*(__m128*)&z[i]) instead of "memory" clobber
.L11:
    movaps   (%rsi,%rax,4), %xmm0   # y, i, vectmp
    addps    (%rdi,%rax,4), %xmm0   # x, i, vectmp
    movaps   %xmm0, (%rdx,%rax,4)   # vectmp, z, i

    addl    $4, %eax        #, i
    addq    $16, %r10       #, ivtmp.19
    addq    $16, %r9        #, ivtmp.21
    addq    $16, %r8        #, ivtmp.22
    cmpl    %eax, %ecx      # i, n
    ja      .L11        #,

r8, r9 и r10 - дополнительные указатели, которые встроенный блок asm 't use.

Вы можете использовать ограничение, которое сообщает gcc, что весь массив произвольной длины является входом или выходом: "m" (*(const struct {char a; char x[];} *) pStr) из ответ @David Wohlferd на asm strlen . Поскольку мы хотим использовать индексированные режимы адресации, у нас будет базовый адрес всех трех массивов в регистрах, и эта форма ограничения запрашивает базовый адрес как операнд, а не указатель на текущую память, на которой он работает.

Это фактически работает без каких-либо дополнительных приращений счетчика внутри цикла:

void add_asm1_dummy_whole_array(const float *restrict x, const float *restrict y,
                             float *restrict z, unsigned n) {
    __m128 vectmp;  // let the compiler choose a scratch register
    for(int i=0; i

Это дает нам тот же внутренний цикл, который мы получили с clobber "memory":

.L19:   # with clobbers like "m" (*(const struct {float a; float x[];} *) y)
    movaps   (%rsi,%rax,4), %xmm0   # y, i, vectmp
    addps    (%rdi,%rax,4), %xmm0   # x, i, vectmp
    movaps   %xmm0, (%rdx,%rax,4)   # vectmp, z, i

    addl    $4, %eax        #, i
    cmpl    %eax, %ecx      # i, n
    ja      .L19        #,

Сообщает компилятору, что каждый блок asm считывает или записывает все массивы, поэтому он может необоснованно останавливать его от чередования с другим кодом (например, после полного разворачивания с низким количеством итераций).


Версия с ограничениями m, , что gcc может развернуть :

#include 
void add_asm1(float *x, float *y, float *z, unsigned n) {
    __m128 vectmp;  // let the compiler choose a scratch register
    for(int i=0; i

Использование [yi] в качестве операнда ввода / вывода +x было бы проще, но запись его таким образом делает меньшее изменение для раскомментации нагрузки в inline asm, вместо этого позволить компилятору получить одно значение в регистрах для нас.

108
задан MetaGuru 1 April 2009 в 21:19
поделиться

4 ответа

update q
set q.QuestionID = a.QuestionID
from QuestionTrackings q
inner join QuestionAnswers a
on q.AnswerID = a.AnswerID
where q.QuestionID is null -- and other conditions you might want

Я рекомендую проверить то, что набор результатов обновить прежде выполняет обновление (тот же запрос, только с выбором):

select *
from QuestionTrackings q
inner join QuestionAnswers a
on q.AnswerID = a.AnswerID
where q.QuestionID is null -- and other conditions you might want

Особенно, ли каждый идентификатор ответа имеет определенно только 1 связанный идентификатор вопроса.

164
ответ дан eglasius 24 November 2019 в 03:30
поделиться

Без нотации обновления-и-соединения (не вся поддержка DBMS, что), используйте:

UPDATE QuestionTrackings
   SET QuestionID = (SELECT QuestionID
                        FROM AnswerTrackings
                        WHERE AnswerTrackings.AnswerID = QuestionTrackings.AnswerID)
   WHERE QuestionID IS NULL
     AND EXISTS(SELECT QuestionID
                        FROM AnswerTrackings
                        WHERE AnswerTrackings.AnswerID = QuestionTrackings.AnswerID)

Часто в запросе как это, необходимо квалифицировать оператор Where с, СУЩЕСТВУЕТ пункт, который содержит подзапрос. Это препятствует тому, чтобы ОБНОВЛЕНИЕ растоптало по строкам, где там не идет ни в какое сравнение (обычно аннулирующий все значения). В этом случае, так как недостающий идентификатор вопроса изменил бы ПУСТОЙ УКАЗАТЕЛЬ на ПУСТОЙ УКАЗАТЕЛЬ, он возможно не имеет значения.

26
ответ дан Jonathan Leffler 24 November 2019 в 03:30
поделиться
UPDATE
    "QuestionTrackings"
SET
    "QuestionID" = (SELECT "QuestionID" FROM "Answers" WHERE "AnswerID"="QuestionTrackings"."AnswerID")
WHERE
    "QuestionID" is NULL
AND ...
12
ответ дан Milen A. Radev 24 November 2019 в 03:30
поделиться

Я думаю, что это должно работать.

UPDATE QuestionTrackings
SET QuestionID = (SELECT QuestionID
                  FROM AnswerTrackings
                  WHERE AnswerTrackings.AnswerID = QuestionTrackings.AnswerID)
WHERE QuestionID IS NULL
AND AnswerID IS NOT NULL;
0
ответ дан 24 November 2019 в 03:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: