Występuje następujący problem przy użyciu Django z MySQL 5.5.22.Aktualizacja MySQL zmieniająca wiele kolumn jest nieatomowa?
Biorąc pod uwagę tabelę z kolumnami id, poziomu i matrycy 2x2 przechowywane jako A11, A12 A21, A22 mam ten wiersz:
id a11 a12 a21 a22 level
324 3 2 5 3 2
otrzymał QS queryset, mam następującą aktualizację:
qs.update(
a11=(b12 * a21 - b11 * a22) * F('a11') + (b11 * a12 - b12 * a11) * F('a21'),
a12=(b12 * a21 - b11 * a22) * F('a12') + (b11 * a12 - b12 * a11) * F('a22'),
a21=(b22 * a21 - b21 * a22) * F('a11') + (b21 * a12 - b22 * a11) * F('a21'),
a22=(b22 * a21 - b21 * a22) * F('a12') + (b21 * a12 - b22 * a11) * F('a22'),
level=(F('level') - 1)
)
dla których Django generuje następujące zapytanie (musi je z db.connection.queries, usunąć, gdy klauzula dla uproszczenia)
UPDATE `storage`
SET
`a21` = (3 * `storage`.`a11`) + (-1 * `storage`.`a21`),
`a22` = (3 * `storage`.`a12`) + (-1 * `storage`.`a22`),
`level` = `storage`.`level` - -1,
`a11` = (2 * `storage`.`a11`) + (-1 * `storage`.`a21`),
`a12` = (2 * `storage`.`a12`) + (-1 * `storage`.`a22`)
A mój wiersz wygląda to potem:
id a11 a12 a21 a22 level
324 2 1 4 3 1
Dla każdego rzędu, a12*a21 - a11*a22 = 1
ma być prawda, i zgodnie z tym, rząd miał być:
id a11 a12 a21 a22 level
324 1 1 4 3 1
Jest co dostaję na SQLite, z Django generującym to samo zapytanie i zajęło mi dużo czasu, aby zorientować się, że MySQL robi coś innego. Z kwerendy wydaje się, że podczas aktualizacji interdepent wielu wierszy, MySQL nie traktuje go jako pojedynczej operacji atomowej, a ponieważ kolumny są aktualizowane, wpływają na wartości zależne od nich. I potwierdził to wydaje się być to, co dzieje się za pomocą następującego kodu w wierszu Python:
>>> a11, a12, a21, a22 = (3, 2, 5, 3)
>>> (2 * a11) + (-1 * a21),\
... (2 * a12) + (-1 * a22),\
... (3 * a11) + (-1 * a21),\
... (3 * a12) + (-1 * a22)
(1, 1, 4, 3)
Jeśli kolumny są aktualizowane po jednym na raz, w tej samej kolejności podanej w zapytaniu:
>>> a11, a12, a21, a22 = (3, 2, 5, 3)
>>> a21 = (3*a11) + (-1*a21)
>>> a22 = (3*a12) + (-1*a22)
>>> a11 = (2*a11) + (-1*a21)
>>> a12 = (2*a12) + (-1*a22)
>>> (a11, a12, a21, a22)
(2, 1, 4, 3)
ten jest naprawdę przerażającym zachowaniem, ponieważ jest to biblioteka przeznaczona do użycia na różnych platformach. Moje pytania to:
- Który z nich robi źle, MySQL lub SQLite? Czy można to uznać za błąd?
- Czego mogę oczekiwać od innych głównych baz danych (Oracle, PostgreSQL i SQLServer)?
- Co mogę zrobić z ORM Django (bez zapytań nieprzetworzonych), aby znormalizować to zachowanie?
edit
Problem jest jasny, ale ciągle szukam rozwiązania. Wyciąganie wszystkich wartości i odpychanie ich nie jest rozwiązaniem dopuszczalnym dla tej konkretnej aplikacji.
To interesujące pytanie. Grałem z nią na [sqlfiddle] (http://sqlfiddle.com/#!2/7f14b/2) i wygląda na to, że MySQL jest jedynym, który zachowuje się w ten sposób. – Chad
Powiązane/duplikaty: http://stackoverflow.com/questions/2203202/sql-update-order-of-valuation – pilcrow
Wyświetl moją zaktualizowaną odpowiedź poniżej. – eggyal