Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Diagnozuj i rozwiązuj typowe problemy podczas korzystania ze sterownika mssql-python do łączenia z SQL Server, Azure SQL Database, Azure SQL Managed Instance oraz bazą danych SQL w Microsoft Fabric.
Problemy z instalacją
Instalacja pip kończy się niepowodzeniem lub pakiet jest kompilowany ze źródeł
Objawy:
error: Microsoft Visual C++ 14.0 or greater is required
ERROR: Failed building wheel for mssql-python
Możliwe przyczyny i rozwiązania:
Brak gotowego koła na twoją platformę
- Sprawdź, czy korzystasz z obsługiwanej wersji Python (wersje 3.10 i nowsze) i platformy. Zobacz cykl życia pomocy technicznej, aby sprawdzić macierz zgodności. Przed instalacją zaktualizuj pip za pomocą
pip install --upgrade pip. W przypadku powtarzalnych środowisk zespołowych używaj zablokowanego przepływu pracy w Powtarzalnych wdrożeniach lub wzorców kontenerowych w Kontenerach i rozwoju lokalnym, aby ograniczyć rozbieżności konfiguracji między lokalnymi maszynami.
- Sprawdź, czy korzystasz z obsługiwanej wersji Python (wersje 3.10 i nowsze) i platformy. Zobacz cykl życia pomocy technicznej, aby sprawdzić macierz zgodności. Przed instalacją zaktualizuj pip za pomocą
Środowisko wirtualne nieaktywowane
- Najpierw aktywuj swoje środowisko wirtualne. Instalacja Python w systemie może powodować błędy uprawnień lub konflikty.
python -m venv .venv .venv\Scripts\activate pip install mssql-python
-
Brakujące biblioteki systemowe Linuksa
- Sterownik wymaga niewielkiego zestawu bibliotek systemowych na Linuksie. Zobacz Zależności specyficzne dla platformy dla pakietów do instalacji.
Konfliktowe instalacje sterowników
Objawy:
Błędy importu lub nieoczekiwane działanie po instalacji mssql-python wraz z pyodbc w tym samym środowisku.
Rozwiązanie:
mssql-python i pyodbc mogą współistnieć. Jeśli zauważysz konflikty, stwórz czyste środowisko wirtualne:
python -m venv .venv --clear
.venv\Scripts\activate
pip install mssql-python
Problemy z połączeniem
Nie można połączyć się z serwerem
Objawy:
OperationalError: [08001] (0) Client unable to establish connection
Możliwe przyczyny i rozwiązania:
Serwer niedostępny
- Sprawdź, czy nazwa serwera i port są poprawne.
- Sprawdź łączność sieciową:
ping servernamelubtelnet servername 1433. - Upewnij się, że zapora sieciowa pozwala na połączenia wychodzące na porcie 1433.
SQL Server nie działa
- Sprawdź, czy usługa SQL Server została uruchomiona.
- Dla nazwanych instancji sprawdź, czy usługa SQL Server Browser jest uruchomiona.
Azure SQL firewall rules
- Dodaj adres IP klienta do reguł zapory Azure SQL w portalu Azure.
- W przypadku Azure SQL Managed Instance upewnij się, że łączysz się z dozwolonej sieci.
# Test basic connectivity
import socket
try:
sock = socket.create_connection(("<server>.database.windows.net", 1433), timeout=5)
print("TCP connection successful")
sock.close()
except Exception as e:
print(f"Cannot reach server: {e}")
Logowanie nie powiodło się
Objawy:
OperationalError: [28000] (18456) Login failed for user 'username'.
Możliwe przyczyny i rozwiązania:
Niedopasowanie trybów uwierzytelniania
- Dla Azure SQL Database, Azure SQL Managed Instance oraz SQL Database in Fabric preferują tryb Microsoft Entra, taki jak
Authentication=ActiveDirectoryDefault. - Jeśli celowo używasz uwierzytelniania SQL, sprawdź, czy serwer na to pozwala i czy używasz właściwego formatu logowania dla danego punktu końcowego.
- Dla Azure SQL Database, Azure SQL Managed Instance oraz SQL Database in Fabric preferują tryb Microsoft Entra, taki jak
Nieprawidłowe dane uwierzytelniające SQL
- Zweryfikowaj nazwę użytkownika i hasło.
- W przypadku usługi Azure SQL podaj pełną nazwę użytkownika:
username@servername.
Użytkownik nie istnieje w bazie danych
- Sprawdź, czy użytkownik ma dostęp do określonej bazy danych.
- Sprawdź, czy logowanie jest przypisane do użytkownika bazy danych.
Uwierzytelnianie nie skonfigurowane
- Używaj uwierzytelniania Microsoft Entra (zalecane):
Authentication=ActiveDirectoryDefault. - Jeśli rozwiązujesz problem z lokalnym SQL Server, który powinien akceptować uwierzytelnianie SQL, sprawdź, czy SQL Server korzysta z uwierzytelniania mieszanego.
- Używaj uwierzytelniania Microsoft Entra (zalecane):
Przekroczenie limitu czasu połączenia
Objawy:
OperationalError: [HYT00] (0) Timeout expired
OperationalError: [HYT01] (0) Connection timeout expired
Możliwe przyczyny i rozwiązania:
Serwer reaguje wolno
- Zwiększ limit czasu połączenia:
conn = mssql_python.connect(connection_string, timeout=60)Opóźnienie sieci
- Sprawdź ścieżkę sieciową do serwera.
- Rozważ użycie krótszej ścieżki sieciowej lub VPN.
Serwer pod dużym obciążeniem
- Spróbuj połączyć się poza godzinami szczytu.
- Skontaktuj się z administratorem swojej bazy danych.
Błędy certyfikatu SSL
Objawy:
OperationalError: [08001] SSL Provider: The certificate chain was issued by an authority that is not trusted
Rozwiązania:
Po pierwsze, należy preferować zaufany certyfikat lub lokalne metody programistyczne opisane w sekcji Kontenery i programowanie lokalne. Używaj TrustServerCertificate=yes tylko do lokalnego rozwoju na serwerze, który kontrolujesz.
Do programowania i testowania z certyfikatem z podpisem własnym:
conn = mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryDefault;"
"Encrypt=yes;"
"TrustServerCertificate=yes;" # Don't use in production
)
Caution
TrustServerCertificate=yes to wyłącznie lokalne rozwiązanie zapasowe. Nie przenoś go do współdzielonych devcontainerów, potoków CI ani wdrożeń produkcyjnych. Szersze wskazówki można znaleźć w artykule Szyfrowanie i certyfikaty.
W środowisku produkcyjnym upewnij się, że odpowiednie certyfikaty są zainstalowane, i użyj:
conn = mssql_python.connect(
"Server=<server>.database.windows.net;"
"Database=<database>;"
"Authentication=ActiveDirectoryDefault;"
"Encrypt=yes;"
"HostnameInCertificate=<server>.domain.com;"
)
Problemy z wykonywaniem zapytań
Tabela lub obiekt nie znaleziony
Objawy:
ProgrammingError: [42S02] (208) Invalid object name 'TableName'.
Możliwe przyczyny i rozwiązania:
Niewłaściwy kontekst bazy danych
# Ensure you're connected to the correct database cursor.execute("SELECT DB_NAME()") print(cursor.fetchone()[0])Schemat nieokreślony
# Use fully qualified name cursor.execute("SELECT * FROM dbo.TableName")Tabela nie istnieje
# Check if table exists cursor.execute(""" SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'TableName' """)
Błąd składniowy
Objawy:
ProgrammingError: [42000] (102) Incorrect syntax near '...'.
Rozwiązania:
Najpierw przetestuj SQL w SSMS, aby zweryfikować składnię
Sprawdź sekwencje ucieczki w ciągach znaków – używaj zapytań parametryzowanych:
# Wrong - vulnerable to syntax issues and SQL injection cursor.execute(f"SELECT * FROM Production.Product WHERE Name = '{name}'") # Correct - use parameters cursor.execute("SELECT * FROM Production.Product WHERE Name = %(name)s", {"name": name})
Błędy parametrów
Objawy:
ProgrammingError: [07001] Wrong number of parameters
Rozwiązania:
Policz symbole zastępcze i parametry - muszą się zgadzać
Wybierz odpowiedni styl parametrów:
# Qmark style - positional cursor.execute("SELECT * FROM Production.Product WHERE ProductID = ? AND Name LIKE ?", (1, "Adjustable%")) print(cursor.fetchone()) # Pyformat style - named cursor.execute("SELECT * FROM Production.Product WHERE ProductID = %(id)s AND Name LIKE %(name)s", {"id": 1, "name": "Adjustable%"}) print(cursor.fetchone())
Problemy z typem danych
Błędy konwersji daty i godziny
Objawy:
DataError: [22007] Invalid datetime format
Rozwiązania:
Używaj obiektów Python datetime zamiast stringów:
from datetime import datetime
cursor.execute("CREATE TABLE #Events (EventDate DATETIME)")
# Wrong - this raises an error for invalid dates
try:
cursor.execute("INSERT INTO #Events (EventDate) VALUES (%(event_date)s)", {"event_date": "2024-13-45"})
except Exception as e:
print(f"Expected error: {e}")
# Correct - use Python datetime objects
cursor.execute("INSERT INTO #Events (EventDate) VALUES (%(event_date)s)", {"event_date": datetime(2024, 3, 15)})
cursor.execute("SELECT EventDate FROM #Events")
print(cursor.fetchone())
Problemy z precyzją dziesiętną
Objawy:
Liczby są obcięte lub nieprawidłowo zaokrąglone.
Rozwiązania:
Zastosowanie decimal.Decimal do precyzyjnych wartości liczbowych:
from decimal import Decimal
cursor.execute("CREATE TABLE #PriceDemo (ListPrice DECIMAL(10,2))")
# Preserve full precision
cursor.execute(
"INSERT INTO #PriceDemo (ListPrice) VALUES (%(list_price)s)",
{"list_price": Decimal("19.99")}
)
Problemy z kodowaniem Unicode
Objawy:
Znaki specjalne pojawiają się zniekształcone lub powodują błędy.
Rozwiązania:
Używaj kolumn NVARCHAR do przechowywania danych Unicode w swojej bazie danych
Przekazuj ciągi bezpośrednio – sterownik obsługuje kodowanie:
cursor.execute("CREATE TABLE #UnicodeDemo (Name NVARCHAR(50))") cursor.execute("INSERT INTO #UnicodeDemo (Name) VALUES (%(name)s)", {"name": "日本語"}) cursor.execute("SELECT Name FROM #UnicodeDemo") print(cursor.fetchone())
Problemy z wydajnością
Powolne wykonywanie zapytań
Możliwe przyczyny i rozwiązania:
Brakujące indeksy: Sprawdź plan wykonywania zapytań w SSMS.
Duże zbiory wyników: Użyj
fetchmany()zamiast :fetchall()cursor.arraysize = 1000 while True: rows = cursor.fetchmany() if not rows: break process_rows(rows)Wyłączenie pulowania połączeń: Włączenie pulowania:
import mssql_python mssql_python.pooling(max_size=20, idle_timeout=300)
Problemy z pamięcią w przypadku dużych wyników
Objawy:
Procesowi Python kończy się pamięć.
Rozwiązania:
Przetwarzanie wyników strumieniowo zamiast ładowania wszystkiego do pamięci:
cursor.execute("SELECT * FROM LargeTable") for row in cursor: # Iterates one row at a time process_row(row)Używaj paginacji po stronie serwera:
page_size = 1000 offset = 0 while True: cursor.execute( "SELECT * FROM LargeTable ORDER BY ID " "OFFSET ? ROWS FETCH NEXT ? ROWS ONLY", (offset, page_size) ) rows = cursor.fetchall() if not rows: break process_rows(rows) offset += page_size
Problemy transakcyjne
Zakres tabeli tymczasowej z automatycznym zatwierdzeniem
Tabele tymczasowe (#tablename) utworzone w ramach transakcji znikają po wycofaniu transakcji. To częste źródło zamieszania, gdy automatyczne zatwierdzanie jest wyłączone (domyślnie):
conn = mssql_python.connect(connection_string) # autocommit=False by default
cursor = conn.cursor()
cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")
# If the connection rolls back (explicit or on error), #TempData disappears
conn.rollback()
# This fails: Invalid object name '#TempData'
cursor.execute("SELECT * FROM #TempData")
Poprawka: Zatwierdzaj natychmiast po utworzeniu tabeli tymczasowej lub użyj trybu automatycznego zatwierdzania:
cursor.execute("CREATE TABLE #TempData (ID INT, Name NVARCHAR(50))")
conn.commit() # Lock in the table definition
cursor.execute("INSERT INTO #TempData VALUES (1, 'test')")
conn.commit()
Instrukcje DDL wymagające trybu autocommit, takie jak CREATE DATABASE, kończą się niepowodzeniem wewnątrz otwartej transakcji. Ustaw autocommit przed ich uruchomieniem:
conn.autocommit = True
cursor.execute("CREATE DATABASE TestDB")
conn.autocommit = False
Transakcja nie została dokonana
Objawy:
Zmiany danych nie utrzymują się po zamknięciu połączenia.
Rozwiązanie:
W przypadku autocommit=False (domyślnie) musisz wywołać commit():
cursor.execute("CREATE TABLE #Products (Name NVARCHAR(100))")
cursor.execute("INSERT INTO #Products (Name) VALUES (%(name)s)", {"name": "Widget"})
conn.commit() # Don't forget this!
Albo użyj trybu automatycznego commitu:
conn = mssql_python.connect(connection_string, autocommit=True)
Błędy zakleszczeń
Objawy:
OperationalError: [40001] (1205) Transaction ... was deadlocked on lock resources with another process
Rozwiązanie:
Logika ponownego pokusu (patrz logika ponownego próbowania) radzi sobie z natychmiastową awarią, ale powtarzające się zakleszczenia wskazują na problem projektowy. Aby naprawić przyczynę źródłową, przechwyć graf blokad i przeanalizować, które instrukcje i typy blokad są zaangażowane. Typowe rozwiązania obejmują zmianę kolejności operacji, tak aby konkurencyjne transakcje zdobywały blokady w tej samej sekwencji, ograniczanie zakresu transakcji oraz dodawanie odpowiednich indeksów skracających czas blokady.
Pełne omówienie analizy zakleszczeń znajduje się w przewodniku Zakleszczenia. Jeśli korzystasz z Azure SQL Database, zobacz Analizowanie zakleszczeń i zapobieganie im.
Problemy z obciążeniem zbiorczym
Naruszenia ograniczeń podczas kopiowania zbiorczego
Objawy:
RuntimeError: CHECK constraint ... Conflict occurred in database ...
RuntimeError: Cannot insert duplicate key ... violation of PRIMARY KEY constraint
Przyczyna:
Dane w twojej partii naruszają ograniczenia tabeli (klucz główny, unikalny, CHECK lub klucz obcy).
Rozwiązanie:
Zweryfikuj dane przed ładowaniem. W przypadku dużych zbiorów danych najpierw załaduj je do tabeli etapowej, a następnie scal je z tabelą docelową:
# Load into staging, then validate
cursor.execute("CREATE TABLE ##Staging (ID INT, Name NVARCHAR(100))")
cursor.bulkcopy("##Staging", rows)
# Check for duplicates before merging
cursor.execute("""
SELECT s.ID FROM ##Staging s
INNER JOIN dbo.Target t ON s.ID = t.ID
""")
dupes = cursor.fetchall()
if dupes:
print(f"Skipping {len(dupes)} duplicate rows")
# Insert only non-duplicate rows
cursor.execute("""
INSERT INTO dbo.Target (ID, Name)
SELECT s.ID, s.Name FROM ##Staging s
WHERE NOT EXISTS (SELECT 1 FROM dbo.Target t WHERE t.ID = s.ID)
""")
conn.commit()
W przypadku wzorców operacji upsert z użyciem tabel przejściowych zobacz artykuł Wzorce ładowania i przemieszczania danych.
Błędy odwzorowania kolumn
Objawy:
RuntimeError: Bulk copy failure - column count mismatch
Przyczyna:
Liczba kolumn w danych nie odpowiada liczbie kolumn w docelowej tabeli lub kolumny są w niewłaściwej kolejności.
Rozwiązanie:
Upewnij się, że Twoje dane dokładnie odpowiadają schematowi tabeli w kolejności i liczbie:
# Check the target table schema
cursor.execute("""
SELECT COLUMN_NAME, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'MyTable'
ORDER BY ORDINAL_POSITION
""")
for col in cursor.fetchall():
print(col)
# Match your data to the column order
rows = [
(1, "Widget", Decimal("19.99")), # Must match table column order
(2, "Gadget", Decimal("29.99")),
]
cursor.bulkcopy("dbo.MyTable", rows)
Niezgodności typów podczas kopiowania masowego
Objawy:
Dane ładują się, ale wartości są obcięte, zaokrąglone lub nieprawidłowe.
Przyczyna:
Wartości w języku Python nie odwzorowują się jednoznacznie na docelowe typy kolumn. Typowe przypadki: wartości float ładowane do kolumn decimal (utrata precyzji) lub zbyt długie ciągi znaków ładowane do kolumn o stałej długości.
Rozwiązanie:
Używaj odpowiednich typów Python, które pasują do twojego schematu:
from decimal import Decimal
# Use Decimal for decimal/numeric columns, not float
rows = [
(1, "Widget", Decimal("19.99")), # Correct
# (1, "Widget", 19.99), # Avoid: float loses precision
]
cursor.bulkcopy("dbo.Products", rows)
Błędy wiązań typów NumPy
Objawy:
Parametry po cichu przestają działać lub powodują błędy typu danych podczas używania typów całkowitych lub zmiennoprzecinkowych NumPy.
Przyczyna:
Typy NumPy, takie jak numpy.int64 i numpy.int32, nie przechodzą isinstance(x, int) w NumPy 2.x. Wnioskowanie typu kierowcy ich nie rozpoznaje, co powoduje nieoczekiwane zachowanie.
Rozwiązanie:
Przekonwertuj wartości numpy na natywne typy Pythona przed powiązaniem:
import numpy as np
# Convert individual values
cursor.execute("SELECT * FROM Production.Product WHERE ProductID = %(product_id)s", {"product_id": int(np.int64(42))})
# Convert DataFrame values
for _, row in df.iterrows():
cursor.execute(
"INSERT INTO #Orders (ProductID, Qty) VALUES (%(product_id)s, %(qty)s)",
{"product_id": int(row["ProductID"]), "qty": int(row["Qty"])}
)
Dla większych zbiorów danych używaj ścieżek integracji Arrow lub Pandas , które obsługują konwersję typów wewnętrznie.
Kopiowanie zbiorcze z tabelami tymczasowymi
Objawy:
cursor.bulkcopy("#TempTable", data) powoduje zgłoszenie RuntimeError: Invalid object name '#TempTable'.
Przyczyna:
bulkcopy() Nie mogę rozwiązać tabel tymczasowych sesji (#tablename) z powodu ograniczeń wyszukiwania metadanych. Globalne tabele tymczasowe (##tablename) i tabele stałe działają.
Rozwiązanie:
Użyj globalnej tabeli tymczasowej lub zwykłej tabeli etapowej:
# Global temp table (visible to all sessions, dropped when last session disconnects)
cursor.execute("CREATE TABLE ##Staging (ID INT, Name NVARCHAR(50))")
cursor.bulkcopy("##Staging", rows)
# Or use a permanent staging table
cursor.execute("CREATE TABLE dbo.Staging (ID INT, Name NVARCHAR(50))")
cursor.bulkcopy("dbo.Staging", rows)
Dla małych zbiorów danych, gdzie preferowana jest tabela temp sesji, używaj executemany() zamiast tego:
cursor.execute("CREATE TABLE #Staging (ID INT, Name NVARCHAR(50))")
cursor.executemany("INSERT INTO #Staging (ID, Name) VALUES (?, ?)", rows)
Problemy z kontenerami i CI
Brakujące biblioteki systemowe na Linuksie
Objawy:
ImportError: libltdl.so.7: cannot open shared object file: No such file or directory
ImportError: libkrb5.so.3: cannot open shared object file
Rozwiązanie:
Zainstaluj wymagane pakiety systemowe. Pakiety różnią się rozkładem:
| Distribution | Zainstaluj polecenie |
|---|---|
| Ubuntu / Debian | sudo apt-get install libltdl7 libkrb5-3 libgssapi-krb5-2 |
| Red Hat / Fedora | sudo dnf install libtool-ltdl krb5-libs |
| Alpine | apk add libltdl krb5-libs |
Przykłady Dockerfile można znaleźć w artykule Kontener i rozwój lokalny.
Błędy SSL w systemie macOS po instalacji
Objawy:
Błędy związane z SSL podczas łączenia z macOS, zwłaszcza na Apple Silicon.
Rozwiązanie:
Zainstaluj OpenSSL przez Homebrew i ustaw flagi linkera:
brew install openssl
export LDFLAGS="-L/opt/homebrew/opt/openssl/lib"
export CPPFLAGS="-I/opt/homebrew/opt/openssl/include"
Narzędzia diagnostyczne
Włącz logowanie sterowników
Użyj mssql_python.setup_logging(), aby włączyć szczegółowe rejestrowanie DEBUG na potrzeby diagnozowania problemów. Wszystkie operacje sterowników są rejestrowane, w tym instrukcje SQL, parametry, wewnętrzne operacje ODBC oraz zmiany stanu połączenia.
import mssql_python
# Enable logging to file (default)
mssql_python.setup_logging()
# Output to stdout (useful for CI/CD and containers)
mssql_python.setup_logging(output='stdout')
# Output to both file and stdout
mssql_python.setup_logging(output='both')
# Custom log file path (must use .txt, .log, or .csv extension)
mssql_python.setup_logging(log_file_path="/var/log/myapp/mssql.log")
Pliki logów są zapisywane w formacie CSV i są automatycznie rotowane po osiągnięciu 512 MB, z zachowaniem pięciu kopii zapasowych. Wrażliwe dane, takie jak hasła i tokeny dostępu, są automatycznie maskowane w danych wyjściowych dziennika.
Aby dodać własne wpisy w dzienniku obok dzienników kierowców, użyj driver_logger:
from mssql_python.logging import driver_logger
mssql_python.setup_logging()
driver_logger.debug("[App] Starting data processing")
driver_logger.error("[App] Failed to process record")
# Your entries appear in the same file with the same format
Caution
Rejestrowanie powoduje narzut wydajnościowy. Włączaj go tylko podczas rozwiązywania problemów, nie domyślnie w produkcji.
Uzyskaj informacje o kierowcy
Pobierz wersję sterownika i szczegóły serwera z aktywnego połączenia:
import mssql_python
conn = mssql_python.connect(connection_string)
# Driver version
print(f"Version: {mssql_python.__version__}")
# Server information
print(f"Server name: {conn.getinfo(mssql_python.SQL_SERVER_NAME)}")
print(f"Database name: {conn.getinfo(mssql_python.SQL_DATABASE_NAME)}")
Sprawdzanie stanu połączenia
Sprawdź, czy połączenie jest nadal otwarte, zanim podejmiesz się do operacji:
try:
cursor = conn.cursor()
cursor.execute("SELECT 1")
print("Connection is open")
except mssql_python.Error:
print("Connection is closed or broken")
Szybkie odniesienie: Typowe błędy
| Błąd | SQLSTATE | Typowa przyczyna | Szybka poprawka |
|---|---|---|---|
| Klient nie może nawiązać połączenia | 08001 | Serwer jest niedostępny | Sprawdź nazwę serwera/port |
| Logowanie nie powiodło się | 28000 | Błędne kwalifikacje | Zweryfikowaj nazwę użytkownika/hasło |
| Upłynął limit czasu | HYT00/HYT01 | Powolna sieć | Zwiększ limit czasu |
| Nieprawidłowa nazwa obiektu | 42S02 | Niewłaściwa tabela/schemat | Używaj w pełni kwalifikowanych nazw |
| Błąd składniowy | 42000 | Błąd SQL | Używanie zapytań sparametryzowanych |
| Naruszenie ograniczeń | 23000 | Naruszenie FK/PK | Sprawdź integralność danych |
| Zakleszczenie | 40001 | Zawartość blokady | Spróbuj ponownie, a następnie przeanalizuj graf deadlocka |