This commit is contained in:
@@ -53,23 +53,23 @@ const osTypes = ref([
|
|||||||
|
|
||||||
const dbTypes = ref([
|
const dbTypes = ref([
|
||||||
{
|
{
|
||||||
label: 'Web application',
|
label: 'Web-приложение',
|
||||||
value: DB_TYPE_WEB,
|
value: DB_TYPE_WEB,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Online transaction processing system',
|
label: 'Система обработки онлайн-транзакций',
|
||||||
value: DB_TYPE_OLTP,
|
value: DB_TYPE_OLTP,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Data warehouse',
|
label: 'Хранилище данных',
|
||||||
value: DB_TYPE_DW,
|
value: DB_TYPE_DW,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Desktop application',
|
label: 'Десктопное приложение',
|
||||||
value: DB_TYPE_DESKTOP,
|
value: DB_TYPE_DESKTOP,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Mixed type of application',
|
label: 'Приложение смешанного типа',
|
||||||
value: DB_TYPE_MIXED,
|
value: DB_TYPE_MIXED,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
@@ -78,26 +78,26 @@ const ramUnits = ref([SIZE_UNIT_TB, SIZE_UNIT_GB, SIZE_UNIT_MB])
|
|||||||
|
|
||||||
const dataStorages = ref([
|
const dataStorages = ref([
|
||||||
{
|
{
|
||||||
label: 'NVMe storage',
|
label: 'Хранилище NVMe',
|
||||||
value: HARD_DRIVE_NVME,
|
value: HARD_DRIVE_NVME,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'SSD storage',
|
label: 'Хранилище SSD',
|
||||||
value: HARD_DRIVE_SSD,
|
value: HARD_DRIVE_SSD,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Network (SAN) storage',
|
label: 'Сетевое хранилище (SAN)',
|
||||||
value: HARD_DRIVE_SAN,
|
value: HARD_DRIVE_SAN,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'HDD storage',
|
label: 'Хранилище HDD',
|
||||||
value: HARD_DRIVE_HDD,
|
value: HARD_DRIVE_HDD,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
const dataSizes = ref([
|
const dataSizes = ref([
|
||||||
{
|
{
|
||||||
label: 'Less than RAM',
|
label: 'Меньше RAM',
|
||||||
value: DB_SIZE_LESS_RAM,
|
value: DB_SIZE_LESS_RAM,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -105,7 +105,7 @@ const dataSizes = ref([
|
|||||||
value: DB_SIZE_MID_RAM,
|
value: DB_SIZE_MID_RAM,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'More than 3x RAM',
|
label: 'Более 3xRAM',
|
||||||
value: DB_SIZE_GREATER_RAM,
|
value: DB_SIZE_GREATER_RAM,
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
@@ -129,81 +129,65 @@ const onSubmit = async () => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<UForm class="space-y-4" :state :schema @submit="onSubmit">
|
<UForm class="space-y-4" :state :schema @submit="onSubmit">
|
||||||
<UFormField
|
<UFormField label="Версия БД" help="Версия PostgreSQL" name="dbVersion">
|
||||||
label="DB version"
|
|
||||||
help="PostgreSQL version (find out via 'SELECT version();')"
|
|
||||||
name="dbVersion"
|
|
||||||
>
|
|
||||||
<USelect v-model="state.dbVersion" :items="dbVersions" class="w-full" />
|
<USelect v-model="state.dbVersion" :items="dbVersions" class="w-full" />
|
||||||
</UFormField>
|
</UFormField>
|
||||||
<UFormField
|
<UFormField
|
||||||
label="OS Type"
|
label="Тип ОС"
|
||||||
help="Operation system of the PostgreSQL server host"
|
help="Операционная система, запускающая PostgreSQL"
|
||||||
name="osType"
|
name="osType"
|
||||||
>
|
>
|
||||||
<USelect v-model="state.osType" :items="osTypes" class="w-full" />
|
<USelect v-model="state.osType" :items="osTypes" class="w-full" />
|
||||||
</UFormField>
|
</UFormField>
|
||||||
<UFormField
|
<UFormField
|
||||||
label="DB type"
|
label="Тип БД"
|
||||||
help="What type of application is PostgreSQL used for"
|
help="Тип приложения, которое обслуживает PostgreSQL"
|
||||||
name="dbType"
|
name="dbType"
|
||||||
>
|
>
|
||||||
<USelect v-model="state.dbType" :items="dbTypes" class="w-full" />
|
<USelect v-model="state.dbType" :items="dbTypes" class="w-full" />
|
||||||
</UFormField>
|
</UFormField>
|
||||||
<div class="flex items-start gap-4">
|
<div class="flex items-start gap-4">
|
||||||
<UFormField
|
<UFormField
|
||||||
label="Total memory (RAM)"
|
label="Оперативная память (RAM)"
|
||||||
help="How much memory can PostgreSQL use"
|
help="Объём оперативной памяти, которую PostgreSQL может использовать"
|
||||||
required
|
required
|
||||||
name="totalMemory"
|
name="totalMemory"
|
||||||
class="grow"
|
class="grow"
|
||||||
>
|
>
|
||||||
<UInputNumber
|
<UInputNumber v-model="state.totalMemory" class="w-full" />
|
||||||
v-model="state.totalMemory"
|
|
||||||
class="w-full"
|
|
||||||
placeholder="Total memory (RAM) (* required)"
|
|
||||||
/>
|
|
||||||
</UFormField>
|
</UFormField>
|
||||||
<UFormField required name="totalMemoryUnit" label="Unit">
|
<UFormField required name="totalMemoryUnit" label="Е.И.">
|
||||||
<USelect v-model="state.totalMemoryUnit" :items="ramUnits" />
|
<USelect v-model="state.totalMemoryUnit" :items="ramUnits" />
|
||||||
</UFormField>
|
</UFormField>
|
||||||
</div>
|
</div>
|
||||||
<UFormField
|
<UFormField
|
||||||
label="Number of CPUs"
|
label="Количество CPU"
|
||||||
help="Number of CPUs, which PostgreSQL can use. CPUs = N threads per core * N cores per socket * N sockets"
|
help="Количество потоков CPU, которые PostgreSQL может использовать. CPU = № потоков на ядро * № ядер на сокет * № сокетов"
|
||||||
name="cpuNum"
|
name="cpuNum"
|
||||||
>
|
>
|
||||||
<UInputNumber
|
<UInputNumber v-model="state.cpuNum" class="w-full" />
|
||||||
v-model="state.cpuNum"
|
|
||||||
class="w-full"
|
|
||||||
placeholder="Number of CPUs"
|
|
||||||
/>
|
|
||||||
</UFormField>
|
</UFormField>
|
||||||
<UFormField
|
<UFormField
|
||||||
label="Number of connections"
|
label="Количество соединений"
|
||||||
help="Maximum number of PostgreSQL client connections"
|
help="Максимальное количество клиентских соединений"
|
||||||
name="connectionNum"
|
name="connectionNum"
|
||||||
>
|
>
|
||||||
<UInputNumber
|
<UInputNumber v-model="state.connectionNum" class="w-full" />
|
||||||
v-model="state.connectionNum"
|
|
||||||
class="w-full"
|
|
||||||
placeholder="Number of connections"
|
|
||||||
/>
|
|
||||||
</UFormField>
|
</UFormField>
|
||||||
<UFormField
|
<UFormField
|
||||||
label="Data storage"
|
label="Хранилище данных"
|
||||||
help="Type of data storage device"
|
help="Тип устройства хранения данных"
|
||||||
name="hdType"
|
name="hdType"
|
||||||
>
|
>
|
||||||
<USelect v-model="state.hdType" :items="dataStorages" class="w-full" />
|
<USelect v-model="state.hdType" :items="dataStorages" class="w-full" />
|
||||||
</UFormField>
|
</UFormField>
|
||||||
<UFormField
|
<UFormField
|
||||||
label="Total data size"
|
label="Объём базы данных"
|
||||||
help="Estimated total size of your database compared to total server RAM"
|
help="Приблизительное отношение объёма хранимых данных к объёму оперативной памяти сервера"
|
||||||
name="dbSize"
|
name="dbSize"
|
||||||
>
|
>
|
||||||
<USelect v-model="state.dbSize" :items="dataSizes" class="w-full" />
|
<USelect v-model="state.dbSize" :items="dataSizes" class="w-full" />
|
||||||
</UFormField>
|
</UFormField>
|
||||||
<UButton size="xl" label="GENERATE" block type="submit" class="h-16" />
|
<UButton size="xl" label="Рассчитать" block type="submit" class="h-16" />
|
||||||
</UForm>
|
</UForm>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,479 +0,0 @@
|
|||||||
import { defineStore } from 'pinia'
|
|
||||||
import { reactive, computed } from 'vue'
|
|
||||||
import { useSettingsStore } from './useSettingsStore'
|
|
||||||
import {
|
|
||||||
DEFAULT_DB_VERSION,
|
|
||||||
OS_LINUX,
|
|
||||||
OS_WINDOWS,
|
|
||||||
OS_MAC,
|
|
||||||
DB_TYPE_WEB,
|
|
||||||
DB_TYPE_OLTP,
|
|
||||||
DB_TYPE_DW,
|
|
||||||
DB_TYPE_DESKTOP,
|
|
||||||
DB_TYPE_MIXED,
|
|
||||||
SIZE_UNIT_GB,
|
|
||||||
HARD_DRIVE_SSD,
|
|
||||||
HARD_DRIVE_HDD,
|
|
||||||
HARD_DRIVE_SAN,
|
|
||||||
HARD_DRIVE_NVME,
|
|
||||||
DB_SIZE_LESS_RAM,
|
|
||||||
DB_SIZE_MID_RAM,
|
|
||||||
DB_SIZE_GREATER_RAM,
|
|
||||||
} from '/src/utils/constants/configuration.js'
|
|
||||||
|
|
||||||
const SIZE_UNIT_MAP = {
|
|
||||||
KB: 1024,
|
|
||||||
MB: 1048576,
|
|
||||||
GB: 1073741824,
|
|
||||||
TB: 1099511627776,
|
|
||||||
PB: 1125899906842624,
|
|
||||||
}
|
|
||||||
|
|
||||||
const DEFAULT_DB_SETTINGS = {
|
|
||||||
default: {
|
|
||||||
['max_worker_processes']: 8,
|
|
||||||
['max_parallel_workers_per_gather']: 2,
|
|
||||||
['max_parallel_workers']: 8,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const initialState = {
|
|
||||||
dbVersion: DEFAULT_DB_VERSION,
|
|
||||||
osType: OS_LINUX,
|
|
||||||
dbType: DB_TYPE_WEB,
|
|
||||||
totalMemory: null,
|
|
||||||
totalMemoryUnit: SIZE_UNIT_GB,
|
|
||||||
cpuNum: null,
|
|
||||||
connectionNum: null,
|
|
||||||
hdType: HARD_DRIVE_SSD,
|
|
||||||
dbSize: DB_SIZE_MID_RAM,
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectCheckpointCompletionTarget = 0.9
|
|
||||||
|
|
||||||
export const useConfigurationStore = defineStore('configuration', () => {
|
|
||||||
const state = reactive({ ...initialState })
|
|
||||||
|
|
||||||
const getConfiguration = computed(() => ({ ...state }))
|
|
||||||
const getDBVersion = computed(() => getConfiguration.value.dbVersion)
|
|
||||||
const getOSType = computed(() => getConfiguration.value.osType)
|
|
||||||
const getDBType = computed(() => getConfiguration.value.dbType)
|
|
||||||
const getTotalMemory = computed(() => getConfiguration.value.totalMemory)
|
|
||||||
const getTotalMemoryUnit = computed(
|
|
||||||
() => getConfiguration.value.totalMemoryUnit,
|
|
||||||
)
|
|
||||||
const getCPUNum = computed(() => getConfiguration.value.cpuNum || null)
|
|
||||||
const getConnectionNum = computed(
|
|
||||||
() => getConfiguration.value.connectionNum || null,
|
|
||||||
)
|
|
||||||
const getHDType = computed(() => getConfiguration.value.hdType)
|
|
||||||
const getDBSize = computed(() => getConfiguration.value.dbSize)
|
|
||||||
const getTotalMemoryInBytes = computed(
|
|
||||||
() => getTotalMemory.value * SIZE_UNIT_MAP[getTotalMemoryUnit.value],
|
|
||||||
)
|
|
||||||
const getTotalMemoryInKb = computed(
|
|
||||||
() => getTotalMemoryInBytes.value / SIZE_UNIT_MAP['KB'],
|
|
||||||
)
|
|
||||||
const getDBDefaultValues = computed(
|
|
||||||
() => DEFAULT_DB_SETTINGS[getDBVersion] || DEFAULT_DB_VERSION.default,
|
|
||||||
)
|
|
||||||
const getIsConfigured = computed(() => !!getTotalMemory.value)
|
|
||||||
const getMaxConnections = computed(
|
|
||||||
() =>
|
|
||||||
getConnectionNum.value ??
|
|
||||||
{
|
|
||||||
[DB_TYPE_WEB]: 200,
|
|
||||||
[DB_TYPE_OLTP]: 300,
|
|
||||||
[DB_TYPE_DW]: 40,
|
|
||||||
[DB_TYPE_DESKTOP]: 20,
|
|
||||||
[DB_TYPE_MIXED]: 100,
|
|
||||||
}[getDBType.value],
|
|
||||||
)
|
|
||||||
const getSharedBuffers = computed(() => {
|
|
||||||
const totalMemoryKb = getTotalMemoryInKb.value
|
|
||||||
|
|
||||||
const val = {
|
|
||||||
[DB_TYPE_WEB]: Math.floor(totalMemoryKb / 4),
|
|
||||||
[DB_TYPE_OLTP]: Math.floor(totalMemoryKb / 4),
|
|
||||||
[DB_TYPE_DW]: Math.floor(totalMemoryKb / 4),
|
|
||||||
[DB_TYPE_DESKTOP]: Math.floor(totalMemoryKb / 16),
|
|
||||||
[DB_TYPE_MIXED]: Math.floor(totalMemoryKb / 4),
|
|
||||||
}[getDBType.value]
|
|
||||||
|
|
||||||
return getDBVersion.value < 10 && OS_WINDOWS === getOSType.value
|
|
||||||
? Math.min(val, (512 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB'])
|
|
||||||
: val
|
|
||||||
})
|
|
||||||
const getHugePages = computed(() =>
|
|
||||||
getOSType.value !== OS_MAC &&
|
|
||||||
getSharedBuffers.value >= (2 * SIZE_UNIT_MAP['GB']) / SIZE_UNIT_MAP['KB']
|
|
||||||
? 'try'
|
|
||||||
: 'off',
|
|
||||||
)
|
|
||||||
const getEffectiveCacheSize = computed(() => {
|
|
||||||
const totalMemoryKb = getTotalMemoryInKb.value
|
|
||||||
|
|
||||||
return {
|
|
||||||
[DB_TYPE_WEB]: Math.floor((totalMemoryKb * 3) / 4),
|
|
||||||
[DB_TYPE_OLTP]: Math.floor((totalMemoryKb * 3) / 4),
|
|
||||||
[DB_TYPE_DW]: Math.floor((totalMemoryKb * 3) / 4),
|
|
||||||
[DB_TYPE_DESKTOP]: Math.floor(totalMemoryKb / 4),
|
|
||||||
[DB_TYPE_MIXED]: Math.floor((totalMemoryKb * 3) / 4),
|
|
||||||
}[getDBType.value]
|
|
||||||
})
|
|
||||||
const getMaintenanceWorkMem = computed(() => {
|
|
||||||
const totalMemoryKb = getTotalMemoryInKb.value
|
|
||||||
// 1. Вычисляем базовое значение по типу БД
|
|
||||||
const baseMemValue = {
|
|
||||||
[DB_TYPE_WEB]: Math.floor(totalMemoryKb / 16),
|
|
||||||
[DB_TYPE_OLTP]: Math.floor(totalMemoryKb / 16),
|
|
||||||
[DB_TYPE_DW]: Math.floor(totalMemoryKb / 8),
|
|
||||||
[DB_TYPE_DESKTOP]: Math.floor(totalMemoryKb / 16),
|
|
||||||
[DB_TYPE_MIXED]: Math.floor(totalMemoryKb / 16),
|
|
||||||
}[getDBType.value]
|
|
||||||
|
|
||||||
// 2. Определяем, действует ли строгое ограничение для Windows
|
|
||||||
const isLegacyWindows =
|
|
||||||
OS_WINDOWS === getOSType.value && getDBVersion.value <= 17
|
|
||||||
|
|
||||||
// 3. Задаем лимит памяти (2GB для старых Windows, иначе 8GB)
|
|
||||||
const maxLimitGb = isLegacyWindows ? 2 : 8
|
|
||||||
const memoryLimit = (maxLimitGb * SIZE_UNIT_MAP['GB']) / SIZE_UNIT_MAP['KB']
|
|
||||||
|
|
||||||
// 4. Если превышен лимит на Windows, вычитаем 1MB, иначе просто возвращаем минимум
|
|
||||||
return baseMemValue >= memoryLimit && isLegacyWindows
|
|
||||||
? memoryLimit - (1 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB']
|
|
||||||
: Math.min(baseMemValue, memoryLimit)
|
|
||||||
})
|
|
||||||
const getCheckpointSegment = computed(() => [
|
|
||||||
{
|
|
||||||
key: 'min_wal_size',
|
|
||||||
value: {
|
|
||||||
[DB_TYPE_WEB]: (1024 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB'],
|
|
||||||
[DB_TYPE_OLTP]: (2048 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB'],
|
|
||||||
[DB_TYPE_DW]: (4096 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB'],
|
|
||||||
[DB_TYPE_DESKTOP]: (100 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB'],
|
|
||||||
[DB_TYPE_MIXED]: (1024 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB'],
|
|
||||||
}[getDBType.value],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'max_wal_size',
|
|
||||||
value: {
|
|
||||||
[DB_TYPE_WEB]: (4096 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB'],
|
|
||||||
[DB_TYPE_OLTP]: (8192 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB'],
|
|
||||||
[DB_TYPE_DW]: (16384 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB'],
|
|
||||||
[DB_TYPE_DESKTOP]: (2048 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB'],
|
|
||||||
[DB_TYPE_MIXED]: (4096 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB'],
|
|
||||||
}[getDBType.value],
|
|
||||||
},
|
|
||||||
])
|
|
||||||
const getWalBuffers = computed(() => {
|
|
||||||
const KB_IN_MB = SIZE_UNIT_MAP['MB'] / SIZE_UNIT_MAP['KB']
|
|
||||||
const baseWal = Math.floor((3 * sharedBuffersValue) / 100)
|
|
||||||
|
|
||||||
return Math.max(
|
|
||||||
32,
|
|
||||||
baseWal > 14 * KB_IN_MB
|
|
||||||
? 16 * KB_IN_MB
|
|
||||||
: Math.min(baseWal, 16 * KB_IN_MB),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
const getDefaultStatisticsTarget = computed(
|
|
||||||
() =>
|
|
||||||
({
|
|
||||||
[DB_TYPE_WEB]: 100,
|
|
||||||
[DB_TYPE_OLTP]: 100,
|
|
||||||
[DB_TYPE_DW]: 500,
|
|
||||||
[DB_TYPE_DESKTOP]: 100,
|
|
||||||
[DB_TYPE_MIXED]: 100,
|
|
||||||
})[getDBType.value],
|
|
||||||
)
|
|
||||||
const getRandomPageCost = computed(() => {
|
|
||||||
// Если база помещается в RAM, поиск на диске не важен
|
|
||||||
if (getDBSize.value === DB_SIZE_LESS_RAM) return 1.1
|
|
||||||
|
|
||||||
// HDD или аналитические БД (DW), не помещающиеся в RAM, требуют дефолтной стоимости (4.0)
|
|
||||||
if (getHDType.value === HARD_DRIVE_HDD || getDBType.value === DB_TYPE_DW)
|
|
||||||
return 4
|
|
||||||
|
|
||||||
return 1.1
|
|
||||||
})
|
|
||||||
const getEffectiveIOConcurrency = computed(() =>
|
|
||||||
getOSType.value === OS_LINUX
|
|
||||||
? {
|
|
||||||
[HARD_DRIVE_HDD]: 2,
|
|
||||||
[HARD_DRIVE_SSD]: 200,
|
|
||||||
[HARD_DRIVE_SAN]: 300,
|
|
||||||
[HARD_DRIVE_NVME]: 1000,
|
|
||||||
}[getHDType.value]
|
|
||||||
: null,
|
|
||||||
)
|
|
||||||
const getParallelSettings = computed(() => {
|
|
||||||
const cpuNum = getCPUNum.value
|
|
||||||
const dbVersion = getDBVersion.value
|
|
||||||
const dbType = getDBType.value
|
|
||||||
|
|
||||||
if (!cpuNum || cpuNum < 4) return []
|
|
||||||
|
|
||||||
const halfCpu = Math.ceil(cpuNum / 2)
|
|
||||||
const cappedWorkers = Math.min(4, halfCpu) // Ограничение в 4 воркера
|
|
||||||
|
|
||||||
const config = [
|
|
||||||
{ key: 'max_worker_processes', value: cpuNum },
|
|
||||||
{
|
|
||||||
key: 'max_parallel_workers_per_gather',
|
|
||||||
value: dbType !== DB_TYPE_DW ? cappedWorkers : halfCpu,
|
|
||||||
},
|
|
||||||
...(dbVersion >= 10
|
|
||||||
? [{ key: 'max_parallel_workers', value: cpuNum }]
|
|
||||||
: []),
|
|
||||||
...(dbVersion >= 11
|
|
||||||
? [{ key: 'max_parallel_maintenance_workers', value: cappedWorkers }]
|
|
||||||
: []),
|
|
||||||
]
|
|
||||||
|
|
||||||
return config
|
|
||||||
})
|
|
||||||
const getWorkMem = computed(() => {
|
|
||||||
const dbDefaultValues = getDBDefaultValues.value
|
|
||||||
|
|
||||||
const maxWorkerProcesses = getParallelSettings.value.find(
|
|
||||||
(param) => param['key'] === 'max_worker_processes',
|
|
||||||
)
|
|
||||||
|
|
||||||
const parallelForWorkMem =
|
|
||||||
maxWorkerProcesses?.value > 0
|
|
||||||
? maxWorkerProcesses.value
|
|
||||||
: dbDefaultValues['max_worker_processes'] > 0
|
|
||||||
? dbDefaultValues['max_worker_processes']
|
|
||||||
: 1
|
|
||||||
|
|
||||||
// Базовая формула расчёта work_mem
|
|
||||||
const baseWorkMem =
|
|
||||||
(getTotalMemoryInKb.value - sharedBuffersValue) /
|
|
||||||
((maxConnectionsValue + parallelForWorkMem) * 3)
|
|
||||||
|
|
||||||
// Коэффициенты для разных типов БД
|
|
||||||
const dbTypeCoefficients = {
|
|
||||||
[DB_TYPE_WEB]: 1,
|
|
||||||
[DB_TYPE_OLTP]: 1,
|
|
||||||
[DB_TYPE_DW]: 0.5,
|
|
||||||
[DB_TYPE_DESKTOP]: 1 / 6,
|
|
||||||
[DB_TYPE_MIXED]: 0.5,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Базовая формула с коэффициентом типа БД
|
|
||||||
const baseWorkMemResult = Math.floor(
|
|
||||||
baseWorkMem * dbTypeCoefficients[dbType],
|
|
||||||
)
|
|
||||||
|
|
||||||
// Корректировка в зависимости от размера БД относительно RAM
|
|
||||||
const sizeAdjustedWorkMem =
|
|
||||||
dbSize === DB_SIZE_LESS_RAM
|
|
||||||
? Math.floor(baseWorkMemResult * 1.3)
|
|
||||||
: dbSize === DB_SIZE_GREATER_RAM
|
|
||||||
? Math.floor(baseWorkMemResult * 0.9)
|
|
||||||
: baseWorkMemResult
|
|
||||||
|
|
||||||
// Применяем минимальное значение 4 MB
|
|
||||||
const minWorkMem = 4 * 1024 // 4 MB в KB
|
|
||||||
const workMemWithMin = Math.max(sizeAdjustedWorkMem, minWorkMem)
|
|
||||||
|
|
||||||
// Применяем ограничение для Windows 64-bit до PostgreSQL 17
|
|
||||||
const winMemoryLimit = 2 * 1024 * 1024 - 1024 // ~2GB - 1MB в KB
|
|
||||||
const workMemResult =
|
|
||||||
osType === OS_WINDOWS && dbVersion <= 17
|
|
||||||
? Math.min(workMemWithMin, winMemoryLimit)
|
|
||||||
: workMemWithMin
|
|
||||||
|
|
||||||
return workMemResult
|
|
||||||
})
|
|
||||||
const getWalLevel = computed(() =>
|
|
||||||
getDBType.value === DB_TYPE_DESKTOP
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
key: 'wal_level',
|
|
||||||
value: 'minimal',
|
|
||||||
},
|
|
||||||
// max_wal_senders must be 0 when wal_level=minimal
|
|
||||||
{
|
|
||||||
key: 'max_wal_senders',
|
|
||||||
value: '0',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: [],
|
|
||||||
)
|
|
||||||
const getJit = computed(() =>
|
|
||||||
getDBVersion.value >= 12 &&
|
|
||||||
[DB_TYPE_WEB, DB_TYPE_OLTP, DB_TYPE_MIXED].includes(getDBType.value)
|
|
||||||
? 'off'
|
|
||||||
: null,
|
|
||||||
)
|
|
||||||
const getWalCompression = computed(() => {
|
|
||||||
const ver = getDBVersion.value
|
|
||||||
|
|
||||||
return ver >= 15 ? 'lz4' : ver >= 10 ? 'on' : null
|
|
||||||
})
|
|
||||||
const getAutovacuumMaxWorkers = computed(() => {
|
|
||||||
const cpuNum = getCPUNum.value
|
|
||||||
|
|
||||||
if (!cpuNum) return null
|
|
||||||
if (cpuNum >= 32) return 5
|
|
||||||
if (cpuNum >= 16) return 4
|
|
||||||
return null
|
|
||||||
})
|
|
||||||
const getAutovacuumWorkMem = computed(() => {
|
|
||||||
const threshold = (2 * SIZE_UNIT_MAP['GB']) / SIZE_UNIT_MAP['KB']
|
|
||||||
|
|
||||||
// Windows 64-bit has a strict 2GB limit up to PostgreSQL 17
|
|
||||||
const winMemoryLimit =
|
|
||||||
(2 * SIZE_UNIT_MAP['GB']) / SIZE_UNIT_MAP['KB'] -
|
|
||||||
(1 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB']
|
|
||||||
|
|
||||||
const isWindowsWithLowLimit =
|
|
||||||
getOSType.value === OS_WINDOWS && getDBVersion.value <= 17
|
|
||||||
|
|
||||||
if (getMaintenanceWorkMem.value < threshold) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isWindowsWithLowLimit) {
|
|
||||||
return Math.min(threshold, winMemoryLimit)
|
|
||||||
}
|
|
||||||
|
|
||||||
return threshold
|
|
||||||
})
|
|
||||||
const getIOMethod = computed(() =>
|
|
||||||
getDBVersion.value < 18
|
|
||||||
? null
|
|
||||||
: getOSType.value === OS_LINUX
|
|
||||||
? 'io_uring'
|
|
||||||
: 'worker',
|
|
||||||
)
|
|
||||||
const getIOWorkers = computed(() => {
|
|
||||||
if (dbVersion < 18 || !cpuNum || ioMethod === 'io_uring') return null
|
|
||||||
|
|
||||||
return Math.max(4, Math.min(32, Math.floor(cpuNum / 4))) || null
|
|
||||||
})
|
|
||||||
const getWarningInfoMessages = computed(() => {
|
|
||||||
const warnings = []
|
|
||||||
const totalMemory = getTotalMemoryInBytes.value
|
|
||||||
|
|
||||||
// Memory warnings
|
|
||||||
if (totalMemory < 256 * SIZE_UNIT_MAP['MB']) {
|
|
||||||
warnings.push('this tool not being optimal', 'for low memory systems')
|
|
||||||
} else if (totalMemory > 100 * SIZE_UNIT_MAP['GB']) {
|
|
||||||
warnings.push(
|
|
||||||
'this tool not being optimal',
|
|
||||||
'for very high memory systems',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advanced features compilation warnings
|
|
||||||
if (getWalCompression.value === 'lz4') {
|
|
||||||
if (warnings.length > 0) warnings.push('')
|
|
||||||
|
|
||||||
warnings.push(
|
|
||||||
'wal_compression = lz4 requires PostgreSQL',
|
|
||||||
'to be compiled with --with-lz4',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getIOMethod.value === 'io_uring') {
|
|
||||||
if (warnings.length > 0) warnings.push('')
|
|
||||||
|
|
||||||
warnings.push(
|
|
||||||
'io_method = io_uring requires PostgreSQL',
|
|
||||||
'to be compiled with --with-liburing',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// I/O Cost Warning for Analytical DBs
|
|
||||||
if (
|
|
||||||
getDBType.value === DB_TYPE_DW &&
|
|
||||||
getHDType.value !== HARD_DRIVE_HDD &&
|
|
||||||
getDBSize.value !== DB_SIZE_LESS_RAM
|
|
||||||
) {
|
|
||||||
const driveName = {
|
|
||||||
[HARD_DRIVE_SSD]: 'SSDs',
|
|
||||||
[HARD_DRIVE_NVME]: 'NVMe drives',
|
|
||||||
[HARD_DRIVE_SAN]: 'SAN storage',
|
|
||||||
}[hdType]
|
|
||||||
|
|
||||||
if (warnings.length > 0) warnings.push('')
|
|
||||||
|
|
||||||
warnings.push(
|
|
||||||
`Cost parameters for Data Warehouses on ${driveName} are left at defaults`,
|
|
||||||
'to avoid catastrophic index scan selections',
|
|
||||||
'Monitor query planner behavior and adjust random_page_cost if necessary',
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return warnings.length > 0 ? ['WARNING', ...warnings] : []
|
|
||||||
})
|
|
||||||
|
|
||||||
function setState(payload) {
|
|
||||||
const settingsStore = useSettingsStore()
|
|
||||||
|
|
||||||
state.value = {
|
|
||||||
dbVersion: parseFloat(payload.dbVersion),
|
|
||||||
osType: payload.osType,
|
|
||||||
dbType: payload.dbType,
|
|
||||||
totalMemory: parseInt(payload.totalMemory, 10),
|
|
||||||
totalMemoryUnit: payload.totalMemoryUnit,
|
|
||||||
cpuNum: payload.cpuNum ? parseInt(payload.cpuNum, 10) : null,
|
|
||||||
connectionNum: payload.connectionNum
|
|
||||||
? parseInt(payload.connectionNum, 10)
|
|
||||||
: null,
|
|
||||||
hdType: payload.hdType,
|
|
||||||
dbSize: payload.dbSize,
|
|
||||||
}
|
|
||||||
|
|
||||||
settingsStore.onSubmitConfiguration()
|
|
||||||
}
|
|
||||||
|
|
||||||
const $reset = () => ({ ...initialState })
|
|
||||||
|
|
||||||
return {
|
|
||||||
state,
|
|
||||||
|
|
||||||
// Getters
|
|
||||||
getDBVersion,
|
|
||||||
getOSType,
|
|
||||||
getDBType,
|
|
||||||
getTotalMemory,
|
|
||||||
getTotalMemoryUnit,
|
|
||||||
getCPUNum,
|
|
||||||
getConnectionNum,
|
|
||||||
getHDType,
|
|
||||||
getDBSize,
|
|
||||||
getTotalMemoryInBytes,
|
|
||||||
getTotalMemoryInKb,
|
|
||||||
getDBDefaultValues,
|
|
||||||
getIsConfigured,
|
|
||||||
getMaxConnections,
|
|
||||||
getSharedBuffers,
|
|
||||||
getHugePages,
|
|
||||||
getEffectiveCacheSize,
|
|
||||||
getMaintenanceWorkMem,
|
|
||||||
getCheckpointSegment,
|
|
||||||
getWalBuffers,
|
|
||||||
getDefaultStatisticsTarget,
|
|
||||||
getRandomPageCost,
|
|
||||||
getEffectiveIOConcurrency,
|
|
||||||
getParallelSettings,
|
|
||||||
getWorkMem,
|
|
||||||
getWalLevel,
|
|
||||||
getJit,
|
|
||||||
getWalCompression,
|
|
||||||
getAutovacuumMaxWorkers,
|
|
||||||
getAutovacuumWorkMem,
|
|
||||||
getIOMethod,
|
|
||||||
getIOWorkers,
|
|
||||||
getWarningInfoMessages,
|
|
||||||
|
|
||||||
// Actions
|
|
||||||
setState,
|
|
||||||
$reset,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import { defineStore } from 'pinia'
|
|
||||||
import { reactive, computed } from 'vue'
|
|
||||||
|
|
||||||
import { TAB_CONFIG, APP_THEMES_LIGHT } from '/src/utils/constants/settings.js'
|
|
||||||
|
|
||||||
const initialState = {
|
|
||||||
tabState: TAB_CONFIG,
|
|
||||||
theme: APP_THEMES_LIGHT,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useSettingsStore = defineStore('settings', () => {
|
|
||||||
const state = reactive({ ...initialState })
|
|
||||||
|
|
||||||
const getSettings = computed(() => state)
|
|
||||||
const getThemeSettings = computed(() => state.theme)
|
|
||||||
const getTabSettings = computed(() => state.tabState)
|
|
||||||
|
|
||||||
function toggleTheme() {
|
|
||||||
state.theme =
|
|
||||||
APP_THEMES_LIGHT === state.theme ? APP_THEMES_DARK : APP_THEMES_LIGHT
|
|
||||||
}
|
|
||||||
function onSubmitConfiguration() {
|
|
||||||
state.tabState = TAB_CONFIG
|
|
||||||
}
|
|
||||||
function $reset() {
|
|
||||||
state = { ...initialState }
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
// STATE
|
|
||||||
state,
|
|
||||||
|
|
||||||
// GETTERS
|
|
||||||
getSettings,
|
|
||||||
getThemeSettings,
|
|
||||||
getTabSettings,
|
|
||||||
toggleTheme,
|
|
||||||
|
|
||||||
// ACTIONS
|
|
||||||
onSubmitConfiguration,
|
|
||||||
$reset,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Reference in New Issue
Block a user