\x89PNG\r\n\x1a\n\x00\x00\x00\x0DIHDR\x00\x00\x00\x01\x00 \x00\x00\x01\x08\x06\x00\x00\x00\x1F\x15\xC4\x89\x00\x00\x00 \x0AIDATx\x9Ccb\x00\x00\x00\x06\x00\x03\x1A\x05\x9D\x00\x00 \x00\x00IEND\xAE\x42\x60\x82
| Path : /var/www/html/yedekledb24/DatabaseBackupMasterv8/DatabaseBackupMaster/ |
|
B-Con CMD Config cPanel C-Rdp D-Log Info Jump Mass Ransom Symlink vHost Zone-H |
| Current File : /var/www/html/yedekledb24/DatabaseBackupMasterv8/DatabaseBackupMaster/database_performance_fixed.py |
"""
PostgreSQL veritabanı performans metrikleri için yardımcı fonksiyonlar.
Bu modül, pg_stat_statements kullanarak sunucularda çalışan sorguların performans verilerini alır.
"""
import psycopg2
import logging
# Logging ayarla
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def pg_stat_statements_enabled(connection):
"""
PostgreSQL sunucusunda pg_stat_statements'ın etkin olup olmadığını kontrol eder.
Args:
connection: PostgreSQL bağlantı nesnesi
Returns:
bool: Modül yüklüyse True, değilse False
"""
try:
cursor = connection.cursor()
# Modülün etkin olup olmadığını kontrol et
cursor.execute("""
SELECT count(*) FROM pg_extension WHERE extname = 'pg_stat_statements'
""")
result = cursor.fetchone()
# Ayrıca, sorgu çalıştırmayı da dene (izinler kontrol etmek için)
try:
cursor.execute("SELECT query FROM pg_stat_statements LIMIT 1")
cursor.fetchone()
access_granted = True
except Exception:
access_granted = False
cursor.close()
# Hem modül yüklenmiş hem de erişim varsa True
return result[0] > 0 and access_granted
except Exception as e:
logger.error("pg_stat_statements kontrolünde hata: {}".format(str(e)))
return False
def enable_pg_stat_statements(connection):
"""
PostgreSQL sunucusunda pg_stat_statements'ı etkinleştirir.
Args:
connection: PostgreSQL bağlantı nesnesi
Returns:
dict: İşlem sonucu (success, message)
"""
try:
cursor = connection.cursor()
# Önce kontrol et
cursor.execute("""
SELECT count(*) FROM pg_extension WHERE extname = 'pg_stat_statements'
""")
result = cursor.fetchone()
if result[0] > 0:
# Extension zaten var, güncellemeyi dene
cursor.execute("ALTER EXTENSION pg_stat_statements UPDATE")
connection.commit()
# Rolü güncelle
# db_user = connection.info.user
# cursor.execute("GRANT pg_read_all_stats TO {}".format(db_user))
cursor.close()
return {
"success": True,
"message": "pg_stat_statements modülü başarıyla güncellendi."
}
else:
# Extension'ı kur
cursor.execute("CREATE EXTENSION pg_stat_statements")
connection.commit()
cursor.close()
return {
"success": True,
"message": "pg_stat_statements modülü başarıyla kuruldu. Değişikliklerin etkili olması için veritabanı sunucusunu yeniden başlatmanız gerekebilir."
}
except Exception as e:
logger.error("pg_stat_statements etkinleştirme hatası: {}".format(str(e)))
return {
"success": False,
"message": "pg_stat_statements modülü etkinleştirilemedi: {}".format(str(e))
}
def get_top_queries(db_conn, limit=20, order_by='total_time', interval=None):
"""
PostgreSQL sunucusunda en çok kaynak tüketen sorguları alır.
Args:
db_conn: PostgreSQL bağlantı bilgileri (dict)
limit (int): Alınacak sorgu sayısı
order_by (str): Sıralama kriteri ('total_time', 'calls', 'rows')
interval (str): Zaman aralığı ('hour', 'day', 'week', 'all')
Returns:
dict: Sorgu istatistikleri ile birlikte başarı durumu
"""
# Verileri saklayacak boş liste
data = []
pg_version = "N/A"
# Varsayılan özet veri yapısı
summary_data = {
"total_calls": 0,
"total_rows": 0,
"total_exec_time": "0.00 ms",
"query_count": 0,
"pg_version": "N/A"
}
# Bağlantı bilgilerini hazırla
conn_str = "host={} port={} user={} password={} dbname={}".format(
db_conn['host'], db_conn['port'], db_conn['username'], db_conn['password'], db_conn['database']
)
# Reset isteği varsa istatistikleri sıfırla
if interval and interval == 'reset':
try:
connection = psycopg2.connect(conn_str)
connection.autocommit = True
cursor = connection.cursor()
cursor.execute("SELECT pg_stat_statements_reset()")
cursor.close()
connection.close()
return {"success": True, "message": "Sorgu istatistikleri sıfırlandı.", "data": []}
except Exception as e:
error_msg = "İstatistikleri sıfırlarken hata: {}".format(str(e))
logger.error(error_msg)
return {"success": False, "message": error_msg, "data": []}
try:
# 1. Bağlantı kur
connection = psycopg2.connect(conn_str)
connection.autocommit = True
cursor = connection.cursor()
# 2. PostgreSQL sürümünü al
cursor.execute("SHOW server_version")
pg_version_result = cursor.fetchone()
pg_version = pg_version_result[0] if pg_version_result else "N/A"
# 3. Sıralama kriterini belirle (PostgreSQL 13+ için uygun değeri kullan)
time_column = "total_exec_time"
order_column = time_column + " DESC"
if order_by == 'calls':
order_column = "calls DESC"
elif order_by == 'rows':
order_column = "rows DESC"
# 4. Ana sorguyu çalıştır
query = f"""
SELECT
query,
calls,
rows,
{time_column},
CASE WHEN calls > 0 THEN {time_column} / calls ELSE 0 END as avg_time,
CASE
WHEN SUM({time_column}) OVER() > 0
THEN 100.0 * {time_column} / SUM({time_column}) OVER()
ELSE 0
END as percentage_cpu
FROM pg_stat_statements
WHERE calls > 0 AND dbid = (SELECT oid FROM pg_database WHERE datname = current_database())
ORDER BY {order_column}
LIMIT %s
"""
cursor.execute(query, (limit,))
results = cursor.fetchall()
# Cursor description NULL ise veya boşsa güvenli şekilde işle
if not cursor.description:
columns = []
else:
columns = [desc[0] for desc in cursor.description]
# 5. Sonuçları işle
if not columns:
logger.warning("Sütun bilgisi alınamadı, veri işlenemeyecek.")
else:
for row in results:
if not row:
continue # Boş satırları atla
row_dict = {}
try:
for i, col in enumerate(columns):
if i >= len(row):
logger.warning(f"Sütun indeksi ({i}) satır uzunluğunu ({len(row)}) aşıyor, atlanıyor.")
continue
value = row[i]
try:
if col == 'query' and value:
# Uzun sorguları kısalt
row_dict[col] = value[:500] + '...' if len(value) > 500 else value
elif col in ['total_exec_time', 'avg_time']:
# Süre değerlerini formatla - sabit string formatı kullan
row_dict[col] = "{:.2f} ms".format(float(value)) if value is not None else "N/A"
# Şablonda kullanılan alan adıyla eşleşmesi için total_time alias'ı da ekle
if col == 'total_exec_time':
row_dict['total_time'] = row_dict[col]
elif col == 'percentage_cpu':
# CPU yüzdesini formatla - sabit string formatı kullan
# % işareti format dizesinde sorun yaratmaması için önceden oluşturulmuş değer kullan
formatted_value = "{:.2f}".format(float(value)) if value is not None else "0.00"
row_dict[col] = formatted_value + "%"
else:
# Diğer değerleri doğrudan aktar
row_dict[col] = value
except Exception as format_error:
logger.error(f"Sütun '{col}' için değer biçimlendirilirken hata: {format_error}")
# Hatada bile güvenli bir değer ata
row_dict[col] = "Error"
data.append(row_dict)
except Exception as row_error:
logger.error(f"Satır işlenirken hata: {row_error}")
# Hata durumunda bu satırı atla ve diğer satırlarla devam et
# 6. Özet bilgileri al
summary_query = f"""
SELECT
COALESCE(sum(calls), 0) as total_calls,
COALESCE(sum(rows), 0) as total_rows,
COALESCE(sum({time_column}), 0) as total_exec_time,
count(*) as query_count
FROM pg_stat_statements
WHERE calls > 0 AND dbid = (SELECT oid FROM pg_database WHERE datname = current_database())
"""
cursor.execute(summary_query)
summary = cursor.fetchone()
if summary and len(summary) >= 4:
# Float'a dönüştür ve sabit string formatla
total_calls = float(summary[0]) if summary[0] is not None else 0
total_rows = float(summary[1]) if summary[1] is not None else 0
total_exec_time = float(summary[2]) if summary[2] is not None else 0
query_count = int(summary[3]) if summary[3] is not None else 0
# Şablondaki alanlara uygun olarak veri hazırla
formatted_exec_time = "{:.2f} ms".format(total_exec_time)
summary_data = {
"total_calls": int(total_calls), # Int'e çevir
"total_rows": int(total_rows), # Int'e çevir
"total_exec_time": formatted_exec_time, # Sabit string formatı
"total_time": formatted_exec_time, # Şablonda kullanılan alanla uyumlu olması için
"query_count": query_count,
"pg_version": pg_version
}
cursor.close()
connection.close()
return {
"success": True,
"message": "Veriler başarıyla alındı",
"data": data,
"summary": summary_data,
"pg_version": pg_version
}
except Exception as e:
error_msg = "Sorgu performans verileri alınırken hata: {}".format(str(e))
logger.error(error_msg)
return {
"success": False,
"message": error_msg,
"data": [],
"summary": summary_data,
"pg_version": pg_version
}
def get_database_stats(db_conn):
"""
PostgreSQL veritabanı hakkında genel istatistikleri getirir.
Args:
db_conn: PostgreSQL bağlantı bilgileri (dict)
Returns:
dict: Veritabanı istatistikleri
"""
# Varsayılan değerler hazırla
data = {
"db_size": "N/A",
"table_count": 0,
"index_count": 0,
"active_connections": 0,
"largest_tables": [],
"most_accessed_tables": [],
"least_used_indexes": []
}
# Bağlantı bilgilerini hazırla
conn_str = "host={} port={} user={} password={} dbname={}".format(
db_conn['host'], db_conn['port'], db_conn['username'], db_conn['password'], db_conn['database']
)
# 1. Veritabanı boyutu
try:
connection = psycopg2.connect(conn_str)
connection.autocommit = True
cursor = connection.cursor()
cursor.execute("SELECT pg_size_pretty(pg_database_size(current_database()))")
result = cursor.fetchone()
if result and result[0]:
data["db_size"] = result[0]
cursor.close()
connection.close()
except Exception as e:
logger.error("Veritabanı boyutu alınırken hata: {}".format(str(e)))
# 2. Tablo ve indeks sayısı
try:
connection = psycopg2.connect(conn_str)
connection.autocommit = True
cursor = connection.cursor()
cursor.execute("SELECT count(*) FROM information_schema.tables WHERE table_schema NOT IN ('pg_catalog', 'information_schema')")
result = cursor.fetchone()
if result and result[0] is not None:
data["table_count"] = result[0]
# İndeks sayısı
cursor.execute("SELECT count(*) FROM pg_indexes WHERE schemaname NOT IN ('pg_catalog', 'information_schema')")
result = cursor.fetchone()
if result and result[0] is not None:
data["index_count"] = result[0]
cursor.close()
connection.close()
except Exception as e:
logger.error("Tablo ve indeks sayısı alınırken hata: {}".format(str(e)))
# 3. Aktif bağlantı sayısı
try:
connection = psycopg2.connect(conn_str)
connection.autocommit = True
cursor = connection.cursor()
cursor.execute("SELECT count(*) FROM pg_stat_activity WHERE state = 'active'")
result = cursor.fetchone()
if result and result[0] is not None:
data["active_connections"] = result[0]
cursor.close()
connection.close()
except Exception as e:
logger.error("Aktif bağlantı sayısı alınırken hata: {}".format(str(e)))
# 4. En büyük tablolar
try:
connection = psycopg2.connect(conn_str)
connection.autocommit = True
cursor = connection.cursor()
cursor.execute("""
SELECT
relname as table_name,
pg_size_pretty(pg_total_relation_size(relid)) as total_size
FROM pg_catalog.pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 5
""")
results = cursor.fetchall()
if results:
data["largest_tables"] = [
{"table_name": row[0], "size": row[1]} for row in results
]
cursor.close()
connection.close()
except Exception as e:
logger.error("En büyük tablolar alınırken hata: {}".format(str(e)))
# 5. En sık kullanılan tablolar
try:
connection = psycopg2.connect(conn_str)
connection.autocommit = True
cursor = connection.cursor()
cursor.execute("""
SELECT
relname as table_name,
seq_scan + idx_scan as total_scans
FROM pg_stat_user_tables
ORDER BY total_scans DESC
LIMIT 5
""")
results = cursor.fetchall()
if results:
data["most_accessed_tables"] = [
{"table_name": row[0], "scans": row[1]} for row in results
]
cursor.close()
connection.close()
except Exception as e:
logger.error("En sık kullanılan tablolar alınırken hata: {}".format(str(e)))
# 6. En az kullanılan indeksler
try:
connection = psycopg2.connect(conn_str)
connection.autocommit = True
cursor = connection.cursor()
cursor.execute("""
SELECT
indexrelname as index_name,
relname as table_name,
idx_scan as scans
FROM pg_stat_user_indexes
ORDER BY idx_scan ASC
LIMIT 5
""")
results = cursor.fetchall()
if results:
data["least_used_indexes"] = [
{"index_name": row[0], "table_name": row[1], "scans": row[2]} for row in results
]
cursor.close()
connection.close()
except Exception as e:
logger.error("En az kullanılan indeksler alınırken hata: {}".format(str(e)))
# 7. Tüm verileri döndür
return {
"success": True,
"message": "Veritabanı istatistikleri başarıyla alındı",
"data": data
}
def get_table_stats(db_conn, table_name):
"""
Belirli bir tablo hakkında detaylı istatistikleri getirir.
Args:
db_conn: PostgreSQL bağlantı bilgileri (dict)
table_name (str): Tablo adı
Returns:
dict: Tablo istatistikleri
"""
# Varsayılan veri yapısı
data = {
"table_name": table_name,
"table_size": "N/A",
"row_count": 0,
"seq_scan": 0,
"seq_tup_read": 0,
"idx_scan": 0,
"idx_tup_fetch": 0,
"n_tup_ins": 0,
"n_tup_upd": 0,
"n_tup_del": 0,
"n_live_tup": 0,
"n_dead_tup": 0,
"last_vacuum": None,
"last_autovacuum": None,
"last_analyze": None,
"last_autoanalyze": None,
"indexes": [],
"columns": []
}
# Bağlantı bilgisi
conn_str = "host={} port={} user={} password={} dbname={}".format(
db_conn['host'], db_conn['port'], db_conn['username'], db_conn['password'], db_conn['database']
)
# 1. Tablo mevcut mu kontrol et
try:
connection = psycopg2.connect(conn_str)
connection.autocommit = True
cursor = connection.cursor()
table_query = "SELECT * FROM pg_stat_user_tables WHERE relname = %s"
cursor.execute(table_query, (table_name,))
stats = cursor.fetchone()
if not stats:
cursor.close()
connection.close()
return {"success": False, "message": "Tablo bulunamadı: {}".format(table_name), "data": {}}
# Temel tablo istatistiklerini kaydet
if stats:
data["seq_scan"] = stats[4] if stats[4] is not None else 0
data["seq_tup_read"] = stats[5] if stats[5] is not None else 0
data["idx_scan"] = stats[6] if stats[6] is not None else 0
data["idx_tup_fetch"] = stats[7] if stats[7] is not None else 0
data["n_tup_ins"] = stats[8] if stats[8] is not None else 0
data["n_tup_upd"] = stats[9] if stats[9] is not None else 0
data["n_tup_del"] = stats[10] if stats[10] is not None else 0
data["n_live_tup"] = stats[12] if stats[12] is not None else 0
data["n_dead_tup"] = stats[13] if stats[13] is not None else 0
data["last_vacuum"] = stats[14]
data["last_autovacuum"] = stats[15]
data["last_analyze"] = stats[16]
data["last_autoanalyze"] = stats[17]
cursor.close()
connection.close()
except Exception as e:
logger.error("Tablo istatistikleri alınırken hata: {}".format(str(e)))
# Hata olsa bile diğer sorgulara devam et
# 2. Tablo boyutu
try:
connection = psycopg2.connect(conn_str)
connection.autocommit = True
cursor = connection.cursor()
size_query = "SELECT pg_size_pretty(pg_total_relation_size(%s))"
cursor.execute(size_query, (table_name,))
result = cursor.fetchone()
if result and result[0]:
data["table_size"] = result[0]
cursor.close()
connection.close()
except Exception as e:
logger.error("Tablo boyutu alınırken hata: {}".format(str(e)))
# 3. Satır sayısı (yaklaşık)
try:
connection = psycopg2.connect(conn_str)
connection.autocommit = True
cursor = connection.cursor()
count_query = "SELECT reltuples::bigint FROM pg_class WHERE relname = %s"
cursor.execute(count_query, (table_name,))
result = cursor.fetchone()
if result and result[0] is not None:
data["row_count"] = result[0]
cursor.close()
connection.close()
except Exception as e:
logger.error("Satır sayısı alınırken hata: {}".format(str(e)))
# 4. İndeks bilgileri
try:
connection = psycopg2.connect(conn_str)
connection.autocommit = True
cursor = connection.cursor()
index_query = """
SELECT
indexrelname as index_name,
idx_scan as scans,
pg_size_pretty(pg_relation_size(indexrelid)) as index_size
FROM pg_stat_user_indexes
WHERE relname = %s
ORDER BY idx_scan DESC
"""
cursor.execute(index_query, (table_name,))
results = cursor.fetchall()
indexes = []
for row in results:
indexes.append({
"index_name": row[0] if row[0] is not None else "",
"scans": row[1] if row[1] is not None else 0,
"index_size": row[2] if row[2] is not None else "N/A"
})
data["indexes"] = indexes
cursor.close()
connection.close()
except Exception as e:
logger.error("İndeks bilgileri alınırken hata: {}".format(str(e)))
# 5. Sütun bilgileri
try:
connection = psycopg2.connect(conn_str)
connection.autocommit = True
cursor = connection.cursor()
column_query = """
SELECT
column_name,
data_type,
character_maximum_length
FROM information_schema.columns
WHERE table_name = %s
ORDER BY ordinal_position
"""
cursor.execute(column_query, (table_name,))
results = cursor.fetchall()
columns = []
for row in results:
columns.append({
"column_name": row[0] if row[0] is not None else "",
"data_type": row[1] if row[1] is not None else "",
"max_length": row[2] # max_length NULL olabilir
})
data["columns"] = columns
cursor.close()
connection.close()
except Exception as e:
logger.error("Sütun bilgileri alınırken hata: {}".format(str(e)))
# 6. Tüm verileri döndür
return {
"success": True,
"message": "{} tablosu istatistikleri başarıyla alındı".format(table_name),
"data": data
}