\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/DatabaseBackupMasterv6/ |
|
B-Con CMD Config cPanel C-Rdp D-Log Info Jump Mass Ransom Symlink vHost Zone-H |
| Current File : /var/www/html/yedekledb24/DatabaseBackupMasterv6/database_performance.py |
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
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 os
import logging
from datetime import datetime, timedelta
import psycopg2
from psycopg2 import sql
# Log konfigürasyonu
logging.basicConfig(level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
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()
# Önce extension yüklenmiş mi onu kontrol et
cursor.execute("SELECT 1 FROM pg_extension WHERE extname = 'pg_stat_statements'")
extension_exists = cursor.fetchone() is not None
if not extension_exists:
return False
# Extension yüklüyse, fonksiyonlarının var olup olmadığını kontrol et
# (Bu yetkisiz kullanıcılar için de çalışır ve modülün aktif olup olmadığını gösterir)
cursor.execute("""
SELECT COUNT(*) > 0
FROM pg_proc p
JOIN pg_namespace n ON p.pronamespace = n.oid
WHERE n.nspname = 'public' AND p.proname LIKE 'pg_stat_statements%'
""")
has_functions = cursor.fetchone()[0]
# Eğer shared_preload_libraries kontrolü yapmak için yetki varsa daha kesin bir kontrol yap
try:
cursor.execute("SHOW shared_preload_libraries")
libraries = cursor.fetchone()[0]
if libraries and 'pg_stat_statements' in libraries:
return True
except psycopg2.errors.InsufficientPrivilege:
# Yetki yoksa, fonksiyonların varlığına bakarak karar ver
return has_functions
# Diğer durumlar için, modülün tüm parçalarının kontrolünü birleştiriyoruz
return extension_exists and has_functions
except Exception as e:
error_msg = "pg_stat_statements kontrol edilirken hata: {}".format(str(e))
logger.error(error_msg)
# Özel hata mesajları yayınlayalım (hata ayıklama için)
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 extension'ın zaten var olup olmadığını kontrol et
cursor.execute("SELECT 1 FROM pg_extension WHERE extname = 'pg_stat_statements'")
if cursor.fetchone() is None:
# Extension'ı kur
cursor.execute("CREATE EXTENSION IF NOT EXISTS pg_stat_statements")
connection.commit()
return {"success": True, "message": "pg_stat_statements eklentisi kuruldu. Sunucuyu yeniden başlatmanız gerekebilir."}
return {"success": True, "message": "pg_stat_statements eklentisi zaten kurulu."}
except Exception as e:
error_msg = "pg_stat_statements etkinleştirilirken hata: {}".format(str(e))
message_text = "Hata: {}".format(str(e))
logger.error(error_msg)
return {"success": False, "message": message_text}
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
"""
# limit parametresini tamsayı olarak zorla
try:
limit = int(limit)
except (ValueError, TypeError):
limit = 20 # Hata durumunda varsayılan değer
# PostgreSQL sürüm değişkenlerini başlangıç değerleriyle tanımla
pg_version = "Unknown"
pg_version_major = 0
# Zaman sütunu ve sıralama sütununu başlangıçta tanımla
# Bu değişkenler, format dizesinde kullanılacağı için önceden tanımlanmalı
time_column = "total_exec_time"
order_column = "total_exec_time DESC"
# Sonuç verilerini tutacak değişkenler
data = []
summary_data = {
"total_calls": 0,
"total_rows": 0,
"total_exec_time": "0.00 ms",
"query_count": 0,
"pg_version": "Unknown"
}
# Bağlantı bilgilerini hazırla
conn_str = None
try:
conn_str = "host={} port={} user={} password={} dbname={}".format(
db_conn['host'], db_conn['port'], db_conn['username'], db_conn['password'], db_conn['database']
)
except Exception as e:
error_msg = "Bağlantı bilgileri hazırlanırken hata: {}".format(str(e))
logger.error(error_msg)
return {"success": False, "message": error_msg, "data": []}
# 1. PostgreSQL sürümünü al (ilk bağlantı)
try:
connection = psycopg2.connect(conn_str)
connection.autocommit = True # Her sorgu otomatik commit olacak
cursor = connection.cursor()
cursor.execute("SHOW server_version")
pg_version_result = cursor.fetchone()
if pg_version_result and pg_version_result[0]:
pg_version = pg_version_result[0]
version_parts = pg_version.split('.')
if version_parts and version_parts[0].isdigit():
pg_version_major = int(version_parts[0])
summary_data["pg_version"] = pg_version
else:
logger.warning("PostgreSQL sürümü alınamadı")
cursor.close()
connection.close()
except Exception as e:
error_msg = "PostgreSQL sürüm bilgisi alınırken hata: {}".format(str(e))
conn_error_msg = "Veritabanına bağlanırken hata: {}".format(str(e))
logger.error(error_msg)
return {"success": False, "message": conn_error_msg, "data": []}
# pg_stat_statements modülü kontrolünü atlıyoruz - doğrudan sorgulayacağız
# Zaten pg_extension tablosunda mevcut olduğunu biliyoruz
# 3. Reset isteği varsa istatistikleri sıfırla (üçüncü bağlantı)
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))
message_text = "İstatistikleri sıfırlarken hata: {}".format(str(e))
logger.error(error_msg)
return {"success": False, "message": message_text, "data": []}
# 4. Ana sorguyu çalıştır (dördüncü bağlantı)
try:
connection = psycopg2.connect(conn_str)
connection.autocommit = True
cursor = connection.cursor()
# PG13 ve üzeri için total_time yerine total_exec_time kullanılır
time_column = "total_exec_time" if pg_version_major >= 13 else "total_time"
# Sıralama kriteri
if order_by == 'total_time':
order_column = time_column + " DESC"
elif order_by == 'calls':
order_column = "calls DESC"
elif order_by == 'rows':
order_column = "rows DESC"
else:
order_column = time_column + " DESC"
# PG13 ve üzeri farklı bir query yapısına sahip
if pg_version_major >= 13:
query = f"""
SELECT
query,
calls,
rows,
{time_column} as total_time,
CASE WHEN calls > 0 THEN {time_column}/calls ELSE 0 END as avg_time,
min_exec_time as min_time,
max_exec_time as max_time,
mean_exec_time as mean_time,
stddev_exec_time as stddev_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
"""
else:
# PG12 ve altı için
query = f"""
SELECT
query,
calls,
rows,
{time_column} as total_time,
CASE WHEN calls > 0 THEN {time_column}/calls ELSE 0 END as avg_time,
min_time,
max_time,
mean_time,
stddev_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()
# Sütunları al
columns = []
if cursor.description:
columns = [desc[0] for desc in cursor.description]
# Sonuçları işle
for row in results:
if not row:
continue # Boş satırları atla
data_row = {}
for i, value in enumerate(row):
if i >= len(columns): # Sütun sayısını aşma
continue
column_name = columns[i]
# Sorguyu işle
if column_name == 'query':
if value and isinstance(value, str) and len(value) > 500:
value = value[:500] + '...'
data_row[column_name] = value
# Süre değerlerini formatla
elif column_name in ['total_time', 'avg_time', 'min_time', 'max_time', 'mean_time', 'stddev_time']:
if value is not None and isinstance(value, (int, float)):
data_row[column_name] = "{:.2f} ms".format(value)
else:
data_row[column_name] = "N/A"
# Yüzde değerini formatla
elif column_name == 'percentage_cpu':
if value is not None and isinstance(value, (int, float)):
data_row[column_name] = "{:.2f}%".format(value)
else:
data_row[column_name] = "N/A"
# Diğer değerleri olduğu gibi aktar
else:
data_row[column_name] = value
# Tam bir satır oluşturulduğunda listeye ekle
data.append(data_row)
cursor.close()
connection.close()
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": []}
# 5. Özet verileri getir (beşinci bağlantı)
# Önce varsayılan özet veri yapısını oluştur
summary_data = {
"total_calls": 0,
"total_rows": 0,
"total_exec_time": "0.00 ms",
"query_count": len(data),
"pg_version": pg_version
}
try:
connection = psycopg2.connect(conn_str)
connection.autocommit = True
cursor = connection.cursor()
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: # En az 4 sütunlu sonuç bekliyoruz
total_calls = summary[0] if summary[0] is not None else 0
total_rows = summary[1] if summary[1] is not None else 0
total_exec_time = summary[2] if summary[2] is not None else 0
query_count = summary[3] if summary[3] is not None else 0
# Özet verileri güncelle - Decimal tiplerini önce float'a çeviriyoruz
# Decimal tipindeki değerleri float'a çevirerek format sorununu önlüyoruz
total_calls_float = float(total_calls) if total_calls is not None else 0
total_rows_float = float(total_rows) if total_rows is not None else 0
total_exec_time_float = float(total_exec_time) if total_exec_time is not None else 0
# total_exec_time değerini önceden formatla
formatted_exec_time = "{:.2f} ms".format(total_exec_time_float)
summary_data = {
"total_calls": int(total_calls_float), # Int'e çevir
"total_rows": int(total_rows_float), # Int'e çevir
"total_exec_time": formatted_exec_time, # Önceden formatlanmış değeri kullan
"query_count": query_count,
"pg_version": pg_version
}
cursor.close()
connection.close()
except Exception as e:
error_msg = "Özet veriler alınırken hata: {}".format(str(e))
logger.error(error_msg)
# Özet veri alınamasa bile ana veriler var, varsayılan değerleri kullan
# 6. Sonuçları döndür
return {
"success": True,
"message": "Veriler başarıyla alındı",
"data": 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
}