Wiem, że możesz wstawić wiele wierszy jednocześnie. Czy istnieje sposób na aktualizację wielu wierszy jednocześnie (jak w jednym zapytaniu) w MySQL?
Edycja: Na przykład mam następujące
Name id Col1 Col2
Row1 1 6 1
Row2 2 2 3
Row3 3 9 5
Row4 4 16 8
Chcę połączyć wszystkie następujące aktualizacje w jedno zapytanie
UPDATE table SET Col1 = 1 WHERE id = 1;
UPDATE table SET Col1 = 2 WHERE id = 2;
UPDATE table SET Col2 = 3 WHERE id = 3;
UPDATE table SET Col1 = 10 WHERE id = 4;
UPDATE table SET Col2 = 12 WHERE id = 4;
mysql
sql
sql-update
Teifion
źródło
źródło
Ponieważ masz wartości dynamiczne, musisz użyć IF lub CASE, aby kolumny zostały zaktualizowane. Robi się trochę brzydki, ale powinien działać.
Korzystając z Twojego przykładu, możesz to zrobić w następujący sposób:
źródło
$commandTxt = 'UPDATE operations SET chunk_finished = CASE id '; foreach ($blockOperationChecked as $operationID => $operationChecked) $commandTxt .= " WHEN $operationID THEN $operationChecked "; $commandTxt .= 'ELSE id END WHERE id IN ('.implode(', ', array_keys(blockOperationChecked )).');';
Pytanie jest stare, ale chciałbym rozszerzyć temat o inną odpowiedź.
Chodzi mi o to, że najprostszym sposobem na osiągnięcie tego jest po prostu zawarcie wielu zapytań transakcją. Przyjęta odpowiedź
INSERT ... ON DUPLICATE KEY UPDATE
to niezły hack, ale należy pamiętać o jej wadach i ograniczeniach:"Field 'fieldname' doesn't have a default value"
ostrzeżenie MySQL, nawet jeśli w ogóle nie wstawisz jednego wiersza. Wpadniesz w kłopoty, jeśli zdecydujesz się zachować surowość i zmienisz ostrzeżenia mysql w wyjątki czasu wykonywania w swojej aplikacji.Przeprowadziłem kilka testów wydajności dla trzech sugerowanych wariantów, w tym
INSERT ... ON DUPLICATE KEY UPDATE
wariantu, wariantu z klauzulą „przypadek / kiedy / wtedy” i naiwnego podejścia do transakcji. Możesz pobrać kod python i wyniki tutaj . Ogólny wniosek jest taki, że wariant z instrukcją case okazuje się dwa razy szybszy niż dwa inne warianty, ale dość trudno jest napisać dla niego poprawny i bezpieczny dla iniekcji kod, więc ja osobiście trzymam się najprostszego podejścia: korzystania z transakcji.Edycja: Ustalenia Dakusana dowodzą, że moje oszacowania wydajności nie są całkiem poprawne. Zapoznaj się z tą odpowiedzią na kolejne, bardziej szczegółowe badania.
źródło
Nie jestem pewien, dlaczego nie wymieniono jeszcze jednej przydatnej opcji:
źródło
Wszystkie poniższe informacje dotyczą InnoDB.
Czuję, że znajomość prędkości 3 różnych metod jest ważna.
Istnieją 3 metody:
Właśnie to przetestowałem, a metoda INSERT wynosiła 6,7x dla mnie szybsza niż metoda TRANSAKCJA. Próbowałem na zestawie zarówno 3000, jak i 30 000 wierszy.
Metoda TRANSACTION nadal musi uruchamiać każde zapytanie indywidualnie, co zajmuje dużo czasu, chociaż podczas wykonywania powoduje zapisanie wyników w pamięci lub coś w tym stylu. Metoda TRANSACTION jest także dość droga zarówno w dziennikach replikacji, jak i dzienników zapytań.
Co gorsza, metoda CASE była o 41,1x wolniejsza niż metoda INSERT z 30 000 rekordów (6,1x wolniejsza niż TRANSACTION). I 75 razy wolniej w MyISAM. Metody INSERT i CASE pobiły nawet przy ~ 1000 rekordów. Nawet przy 100 rekordach metoda CASE jest BARELY szybsza.
Ogólnie rzecz biorąc, uważam, że metoda INSERT jest zarówno najlepsza, jak i najłatwiejsza w użyciu. Zapytania są mniejsze i łatwiejsze do odczytania i podejmują tylko 1 zapytanie działania. Dotyczy to zarówno InnoDB, jak i MyISAM.
Materiały dodatkowe:
Rozwiązaniem problemu non-default-polowego INSERT jest tymczasowo wyłączyć odpowiednie tryby SQL:
SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TABLES",""),"STRICT_ALL_TABLES","")
. Pamiętaj, aby zapisaćsql_mode
pierwszy, jeśli planujesz go cofnąć.Co do innych komentarzy, które widziałem, że auto_increment idzie w górę za pomocą metody INSERT, wydaje się, że tak jest w InnoDB, ale nie w MyISAM.
Kod do uruchomienia testów jest następujący. Wysyła również pliki .SQL, aby usunąć narzut interpretera php
źródło
Użyj tabeli tymczasowej
źródło
To powinno na ciebie zadziałać.
W podręczniku MySQL znajduje się odniesienie do wielu tabel.
źródło
Dlaczego nikt nie wspomina o wielu instrukcjach w jednym zapytaniu ?
W php używasz
multi_query
metody instancji mysqli.Z podręcznika php
Oto wynik w porównaniu z innymi 3 metodami w aktualizacji 30 000 raw. Kod można znaleźć tutaj, który jest oparty na odpowiedzi z @Dakusan
Transakcja: 5.5194580554962
Wkładka: 0.20669293403625
Obudowa: 16.474853992462
Multi: 0,0412278175354
Jak widać, zapytanie z wieloma instrukcjami jest wydajniejsze niż najwyższa odpowiedź.
Jeśli pojawi się taki komunikat o błędzie:
Może być konieczne zwiększenie
max_allowed_packet
pliku konfiguracyjnego mysql, który znajduje się na moim komputerze,/etc/mysql/my.cnf
a następnie ponowne uruchomienie mysqld.źródło
$mysqli->multi_query($sql)
zajęło „0” sekund. Jednak kolejne zapytania nie powiodły się, przez co uczyniłem z tego osobny „program”.Istnieje ustawienie, które można zmienić, nazywane „instrukcją wielokrotną”, które wyłącza „mechanizm bezpieczeństwa” MySQL zaimplementowany w celu zapobiegania (więcej niż jednemu) poleceniu wstrzyknięcia. Typowa dla „genialnej” implementacji MySQL, zapobiega także wydajnym zapytaniom użytkownika.
Tutaj ( http://dev.mysql.com/doc/refman/5.1/en/mysql-set-server-option.html ) znajduje się kilka informacji na temat implementacji ustawienia C.
Jeśli używasz PHP, możesz używać mysqli do wykonywania wielu instrukcji (myślę, że php jest już dostępny z mysqli)
Mam nadzieję, że to pomaga.
źródło
mysqli::begin_transaction(..)
przed wysłaniem zapytania imysql::commit(..)
po nim. Lub użyjSTART TRANSACTION
jako pierwszej iCOMMIT
ostatniej instrukcji w samym zapytaniu.Możesz aliasować tę samą tabelę, aby uzyskać identyfikatory, które chcesz wstawić (jeśli wykonujesz aktualizację wiersz po wierszu:
Ponadto powinno wydawać się oczywiste, że możesz także aktualizować z innych tabel. W takim przypadku aktualizacja pełni również funkcję instrukcji „SELECT”, podając dane z określonej tabeli. W zapytaniu wyraźnie podajesz wartości aktualizacji, więc druga tabela pozostaje nienaruszona.
źródło
Możesz także być zainteresowany korzystaniem z połączeń w aktualizacjach, co jest również możliwe.
Edycja: jeśli wartości, które aktualizujesz, nie pochodzą z innej bazy danych, musisz wydać wiele zapytań o aktualizację.
źródło
A teraz prosty sposób
źródło
posługiwać się
Proszę zanotować:
źródło
Poniższe zaktualizuje wszystkie wiersze w jednej tabeli
Następny zaktualizuje wszystkie wiersze, w których wartość kolumny 2 jest większa niż 5
Istnieje cały przykład Unkwntech dotyczący aktualizacji więcej niż jednej tabeli
źródło
Tak .. jest to możliwe przy użyciu instrukcji INSERT ON DUPLICATE KEY UPDATE sql .. składnia: INSERT INTO nazwa_tabeli (a, b, c) VALUES (1,2,3), (4,5,6) ON DUPLICATE KEY UPDATE a = WARTOŚCI (a), b = WARTOŚCI (b), c = WARTOŚCI (c)
źródło
To powinno osiągnąć to, czego szukasz. Po prostu dodaj więcej identyfikatorów. Przetestowałem to.
źródło
// Po prostu budujesz go w PHP
Możesz więc zaktualizować tabelę otworów za pomocą jednego zapytania
źródło
something
sięsomething
)