FEAT: calculator prototype
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-09-08 01:19:32 +03:00
parent 91e293eccd
commit 9746e0fa33
3 changed files with 658 additions and 24 deletions
+1 -2
View File
@@ -6,7 +6,6 @@ import { onMounted } from 'vue'
import { useUpdateApp } from './composables/useUpdateApp.js' import { useUpdateApp } from './composables/useUpdateApp.js'
const route = useRoute() const route = useRoute()
const DEV = import.meta.env.DEV
onMounted(() => { onMounted(() => {
useThemeColor() useThemeColor()
@@ -19,7 +18,7 @@ onMounted(() => {
<UContainer> <UContainer>
<Header /> <Header />
<UMain class="p-4"> <UMain class="p-4">
<RouterView :key="route.fullPath" /> <RouterView :key="route.path" />
</UMain> </UMain>
</UContainer> </UContainer>
</UApp> </UApp>
+92 -22
View File
@@ -22,45 +22,115 @@ import {
DB_SIZE_GREATER_RAM, DB_SIZE_GREATER_RAM,
} from '../utils/constants/configuration' } from '../utils/constants/configuration'
import { validationSchema as schema } from '../utils/validation' import { validationSchema as schema } from '../utils/validation'
import { useRoute, useRouter } from 'vue-router'
import { calculateSettings } from '../utils/calculator'
const dbVersions = ref(DB_VERSIONS) const route = useRoute()
const router = useRouter()
const osTypes = ref([OS_LINUX, OS_WINDOWS, OS_MAC]) const query = route.query
const dbVersions = ref(
DB_VERSIONS.map((version) => ({
label: String(version),
value: version,
})),
)
const osTypes = ref([
{
label: 'Linux',
value: OS_LINUX,
},
{
label: 'OS X',
value: OS_MAC,
},
{
label: 'Windows',
value: OS_WINDOWS,
},
])
const dbTypes = ref([ const dbTypes = ref([
DB_TYPE_WEB, {
DB_TYPE_OLTP, label: 'Web application',
DB_TYPE_DW, value: DB_TYPE_WEB,
DB_TYPE_DESKTOP, },
DB_TYPE_MIXED, {
label: 'Online transaction processing system',
value: DB_TYPE_OLTP,
},
{
label: 'Data warehouse',
value: DB_TYPE_DW,
},
{
label: 'Desktop application',
value: DB_TYPE_DESKTOP,
},
{
label: 'Mixed type of application',
value: DB_TYPE_MIXED,
},
]) ])
const ramUnits = ref([SIZE_UNIT_TB, SIZE_UNIT_GB, SIZE_UNIT_MB]) const ramUnits = ref([SIZE_UNIT_TB, SIZE_UNIT_GB, SIZE_UNIT_MB])
const dataStorages = ref([ const dataStorages = ref([
HARD_DRIVE_HDD, {
HARD_DRIVE_SSD, label: 'NVMe storage',
HARD_DRIVE_SAN, value: HARD_DRIVE_NVME,
HARD_DRIVE_NVME, },
{
label: 'SSD storage',
value: HARD_DRIVE_SSD,
},
{
label: 'Network (SAN) storage',
value: HARD_DRIVE_SAN,
},
{
label: 'HDD storage',
value: HARD_DRIVE_HDD,
},
]) ])
const dataSizes = ref([DB_SIZE_LESS_RAM, DB_SIZE_MID_RAM, DB_SIZE_GREATER_RAM]) const dataSizes = ref([
{
label: 'Less than RAM',
value: DB_SIZE_LESS_RAM,
},
{
label: '1x - 3x RAM',
value: DB_SIZE_MID_RAM,
},
{
label: 'More than 3x RAM',
value: DB_SIZE_GREATER_RAM,
},
])
const state = reactive({ const state = reactive({
dbVersion: 18, dbVersion: query?.dbVersion ? parseInt(query.dbVersion) : 18,
osType: OS_LINUX, osType: query?.osType ?? OS_LINUX,
dbType: DB_TYPE_WEB, dbType: query?.dbType ?? DB_TYPE_WEB,
totalMemory: undefined, totalMemory: query?.totalMemory ? parseInt(query.totalMemory) : undefined,
totalMemoryUnit: SIZE_UNIT_GB, totalMemoryUnit: query?.totalMemoryUnit ?? SIZE_UNIT_GB,
cpuNum: 1, cpuNum: query?.cpuNum ? parseInt(query.cpuNum) : 1,
connectionNum: 100, connectionNum: query?.connectionNum ? parseInt(query.connectionNum) : 100,
hdType: HARD_DRIVE_NVME, hdType: query?.hdType ?? HARD_DRIVE_NVME,
dbSize: DB_SIZE_LESS_RAM, dbSize: query?.dbSize ?? DB_SIZE_LESS_RAM,
}) })
const onSubmit = async () => {
await router.push({ name: 'Index', query: { ...state } })
console.log(calculateSettings({ ...state }))
}
</script> </script>
<template> <template>
<UForm class="space-y-4" :state :schema> <UForm class="space-y-4" :state :schema @submit="onSubmit">
<UFormField <UFormField
label="DB version" label="DB version"
help="PostgreSQL version (find out via 'SELECT version();')" help="PostgreSQL version (find out via 'SELECT version();')"
+565
View File
@@ -0,0 +1,565 @@
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 './constants/configuration'
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,
},
}
export function calculateSettings({
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 totalMemoryInBytes = totalMemory * SIZE_UNIT_MAP[totalMemoryUnit]
const totalMemoryInKb = totalMemoryInBytes / SIZE_UNIT_MAP['KB']
const dbDefaultValues =
DEFAULT_DB_SETTINGS[dbVersion] || DEFAULT_DB_SETTINGS.default
const isConfigured = !!totalMemory
const maxConnections = connectionNum
? connectionNum
: {
[DB_TYPE_WEB]: 200,
[DB_TYPE_OLTP]: 300,
[DB_TYPE_DW]: 40,
[DB_TYPE_DESKTOP]: 20,
[DB_TYPE_MIXED]: 100,
}[dbType]
const effectiveCacheSize = {
[DB_TYPE_WEB]: Math.floor((totalMemoryInKb * 3) / 4),
[DB_TYPE_OLTP]: Math.floor((totalMemoryInKb * 3) / 4),
[DB_TYPE_DW]: Math.floor((totalMemoryInKb * 3) / 4),
[DB_TYPE_DESKTOP]: Math.floor(totalMemoryInKb / 4),
[DB_TYPE_MIXED]: Math.floor((totalMemoryInKb * 3) / 4),
}[dbType]
const checkpointSegments = [
{
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'],
}[dbType],
},
{
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'],
}[dbType],
},
]
const checkpointCompletionTarget = 0.9
const defaultStatisticsTarget = {
[DB_TYPE_WEB]: 100,
[DB_TYPE_OLTP]: 100,
[DB_TYPE_DW]: 500,
[DB_TYPE_DESKTOP]: 100,
[DB_TYPE_MIXED]: 100,
}[dbType]
const walLevel =
dbType === 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 jit =
dbVersion >= 12 &&
[DB_TYPE_WEB, DB_TYPE_OLTP, DB_TYPE_MIXED].includes(dbType)
? 'off'
: null
const sharedBuffers = selectSharedBuffers(
totalMemoryInKb,
dbType,
osType,
dbVersion,
)
const hugePages = selectHugePages(sharedBuffers, osType)
const maintenanceWorkMem = selectMaintenanceWorkMem(
totalMemoryInKb,
dbType,
osType,
dbVersion,
)
const walBuffers = selectWalBuffers(sharedBuffers)
const randomPageCost = selectRandomPageCost(hdType, dbSize, dbType)
const effectiveIoConcurrency = selectEffectiveIoConcurrency(osType, hdType)
const parallelSettings = selectParallelSettings(dbVersion, dbType, cpuNum)
const workMem = selectWorkMem(
totalMemoryInKb,
sharedBuffers,
maxConnections,
parallelSettings,
dbDefaultValues,
dbType,
osType,
dbVersion,
dbSize,
)
const walCompression = selectWalCompression(dbVersion)
const autovacuumMaxWorkers = selectAutovacuumMaxWorkers(cpuNum)
const autovacuumWorkMem = selectAutovacuumWorkMem(
maintenanceWorkMem,
osType,
dbVersion,
)
const ioMethod = selectIoMethod(dbVersion, osType)
const ioWorkers = selectIoWorkers(dbVersion, cpuNum, ioMethod)
const warningInfoMessages = selectWarningInfoMessages(
totalMemoryInBytes,
walCompression,
ioMethod,
dbType,
hdType,
dbSize,
)
return {
totalMemoryInBytes,
totalMemoryInKb,
dbDefaultValues,
isConfigured,
maxConnections,
effectiveCacheSize,
checkpointSegments,
checkpointCompletionTarget,
defaultStatisticsTarget,
walLevel,
jit,
sharedBuffers,
hugePages,
walBuffers,
randomPageCost,
effectiveIoConcurrency,
parallelSettings,
workMem,
walCompression,
autovacuumMaxWorkers,
autovacuumWorkMem,
ioMethod,
ioWorkers,
warningInfoMessages,
}
}
function selectSharedBuffers(totalMemoryKb, dbType, osType, dbVersion) {
let sharedBuffersValue = {
[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),
}[dbType]
if (dbVersion < 10 && OS_WINDOWS === osType) {
// Limit shared_buffers to 512MB on Windows
const winMemoryLimit = (512 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB']
if (sharedBuffersValue > winMemoryLimit) {
sharedBuffersValue = winMemoryLimit
}
}
return sharedBuffersValue
}
function selectHugePages(sharedBuffersValue, osType) {
// macOS does not support PostgreSQL huge pages
if (osType === OS_MAC) {
return 'off'
}
const hugePageThreshold = (2 * SIZE_UNIT_MAP['GB']) / SIZE_UNIT_MAP['KB']
return sharedBuffersValue >= hugePageThreshold ? 'try' : 'off'
}
function selectMaintenanceWorkMem(totalMemoryKb, dbType, osType, dbVersion) {
let maintenanceWorkMemValue = {
[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),
}[dbType]
// Default cap is 8GB on modern servers with lots of memory
let memoryLimit = (8 * SIZE_UNIT_MAP['GB']) / SIZE_UNIT_MAP['KB']
// Windows 64-bit has a strict 2GB limit up to PostgreSQL 17
if (OS_WINDOWS === osType && dbVersion <= 17) {
memoryLimit = (2 * SIZE_UNIT_MAP['GB']) / SIZE_UNIT_MAP['KB']
}
if (maintenanceWorkMemValue >= memoryLimit) {
if (OS_WINDOWS === osType && dbVersion <= 17) {
// 2048MB (2 GB) will raise an error on Windows PG <= 17, so we need to remove 1 MB from it
maintenanceWorkMemValue =
memoryLimit - (1 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB']
} else {
maintenanceWorkMemValue = memoryLimit
}
}
return maintenanceWorkMemValue
}
function selectWalBuffers(sharedBuffersValue) {
// Follow auto-tuning guideline for wal_buffers added in 9.1, where it's
// set to 3% of shared_buffers up to a maximum of 16MB.
let walBuffersValue = Math.floor((3 * sharedBuffersValue) / 100)
const maxWalBuffer = (16 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB']
if (walBuffersValue > maxWalBuffer) {
walBuffersValue = maxWalBuffer
}
// It's nice of wal_buffers is an even 16MB if it's near that number. Since
// that is a common case on Windows, where shared_buffers is clipped to 512MB,
// round upwards in that situation
const walBufferNearValue = (14 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB']
if (walBuffersValue > walBufferNearValue && walBuffersValue < maxWalBuffer) {
walBuffersValue = maxWalBuffer
}
// if less, than 32 kb, than set it to minimum
if (walBuffersValue < 32) {
walBuffersValue = 32
}
return walBuffersValue
}
function selectRandomPageCost(hdType, dbSize, dbType) {
// If the entire database fits in RAM, all read requests will be served
// from the OS page cache. Disk seek time (even for HDD) becomes irrelevant.
if (dbSize === DB_SIZE_LESS_RAM) {
return 1.1
}
// HDD always gets 4.0
if (hdType === HARD_DRIVE_HDD) {
return 4
}
// For Data Warehouses that don't fit in RAM, a low random_page_cost is dangerous.
// It causes the planner to pick index scans for large data retrievals, which
// are much slower on physical SSDs than sequential scans.
// Return 4.0 (the Postgres default) to prevent this harm
if (dbType === DB_TYPE_DW) {
return 4
}
return 1.1
}
function selectEffectiveIoConcurrency(osType, hdType) {
if (osType !== OS_LINUX) {
return null
}
return {
[HARD_DRIVE_HDD]: 2,
[HARD_DRIVE_SSD]: 200,
[HARD_DRIVE_SAN]: 300,
[HARD_DRIVE_NVME]: 1000,
}[hdType]
}
function selectParallelSettings(dbVersion, dbType, cpuNum) {
if (!cpuNum || cpuNum < 4) {
return []
}
let workersPerGather = Math.ceil(cpuNum / 2)
if (dbType !== DB_TYPE_DW && workersPerGather > 4) {
workersPerGather = 4 // no clear evidence, that each new worker will provide big benefit for each noew core
}
let config = [
{
key: 'max_worker_processes',
value: cpuNum,
},
{
key: 'max_parallel_workers_per_gather',
value: workersPerGather,
},
]
if (dbVersion >= 10) {
config.push({
key: 'max_parallel_workers',
value: cpuNum,
})
}
if (dbVersion >= 11) {
let parallelMaintenanceWorkers = Math.ceil(cpuNum / 2)
if (parallelMaintenanceWorkers > 4) {
parallelMaintenanceWorkers = 4 // no clear evidence, that each new worker will provide big benefit for each noew core
}
config.push({
key: 'max_parallel_maintenance_workers',
value: parallelMaintenanceWorkers,
})
}
return config
}
function selectWorkMem(
totalMemoryKb,
sharedBuffersValue,
maxConnectionsValue,
parallelSettingsValue,
dbDefaultValues,
dbType,
osType,
dbVersion,
dbSize,
) {
const parallelForWorkMem = (() => {
if (parallelSettingsValue.length) {
const maxWorkerProcesses = parallelSettingsValue.find(
(param) => param['key'] === 'max_worker_processes',
)
if (
maxWorkerProcesses &&
maxWorkerProcesses['value'] &&
maxWorkerProcesses['value'] > 0
) {
return maxWorkerProcesses['value']
}
}
if (
dbDefaultValues['max_worker_processes'] &&
dbDefaultValues['max_worker_processes'] > 0
) {
return dbDefaultValues['max_worker_processes']
}
return 1
})()
// work_mem is assigned any time a query calls for a sort, or a hash, or any other structure that needs a space allocation, which can happen multiple times per query. So you're better off assuming max_connections * 2 or max_connections * 3 is the amount of RAM that will actually use in reality. At the very least, you need to subtract shared_buffers from the amount you're distributing to connections in work_mem.
// The other thing to consider is that there's no reason to run on the edge of available memory. If you do that, there's a very high risk the out-of-memory killer will come along and start killing PostgreSQL backends. Always leave a buffer of some kind in case of spikes in memory usage. So your maximum amount of memory available in work_mem should be (RAM - shared_buffers) / ((max_connections + max_worker_processes) * 3).
const workMemValue =
(totalMemoryKb - sharedBuffersValue) /
((maxConnectionsValue + parallelForWorkMem) * 3)
let workMemResult = {
[DB_TYPE_WEB]: Math.floor(workMemValue),
[DB_TYPE_OLTP]: Math.floor(workMemValue),
[DB_TYPE_DW]: Math.floor(workMemValue / 2),
[DB_TYPE_DESKTOP]: Math.floor(workMemValue / 6),
[DB_TYPE_MIXED]: Math.floor(workMemValue / 2),
}[dbType]
if (dbSize === DB_SIZE_LESS_RAM) {
// OS Cache is underutilized because the DB fits entirely in RAM.
// We can safely boost work_mem by 30% to speed up sorts/hashes.
workMemResult = Math.floor(workMemResult * 1.3)
} else if (dbSize === DB_SIZE_GREATER_RAM) {
// OS Cache is under massive pressure. We must protect memory.
// Reduce work_mem by 10% to provide a wider safety net against OOM spikes.
workMemResult = Math.floor(workMemResult * 0.9)
}
// Modern floor limit: 4 MB minimum to prevent disk-spill for simple queries
const minWorkMem = (4 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB']
if (workMemResult < minWorkMem) {
workMemResult = minWorkMem
}
// Windows 64-bit has a strict 2GB limit up to PostgreSQL 17
if (osType === OS_WINDOWS && dbVersion <= 17) {
const winMemoryLimit =
(2 * SIZE_UNIT_MAP['GB']) / SIZE_UNIT_MAP['KB'] -
(1 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB']
if (workMemResult > winMemoryLimit) {
workMemResult = winMemoryLimit
}
}
return workMemResult
}
function selectWalCompression(dbVersion) {
// PG 15+ introduced lz4 and zstd support. lz4 is significantly faster
// and lighter on CPU than the native pglz algorithm. Standard package
// installations compile with lz4 support by default.
if (dbVersion >= 15) {
return 'lz4'
}
// For PG 10 through 14, 'on' safely enables pglz compression.
if (dbVersion >= 10) {
return 'on'
}
return null
}
function selectAutovacuumMaxWorkers(cpuNum) {
// PG default is 3. We only safely scale it up on heavier servers.
if (!cpuNum) return null
if (cpuNum >= 32) return 5
if (cpuNum >= 16) return 4
return null
}
function selectAutovacuumWorkMem(maintenanceWorkMemValue, osType, dbVersion) {
let autovacuumWorkMemValue = null
// By default, autovacuum_work_mem is -1 (uses maintenance_work_mem).
// Because we safely raised maintenance_work_mem to up to 8GB, letting 3-5 background
// workers each consume 8GB would cause severe OOM risks. We explicitly cap
// background vacuum memory to 2GB max per worker.
const threshold = (2 * SIZE_UNIT_MAP['GB']) / SIZE_UNIT_MAP['KB']
if (maintenanceWorkMemValue >= threshold) {
autovacuumWorkMemValue = threshold
}
// Windows 64-bit has a strict 2GB limit up to PostgreSQL 17
if (
autovacuumWorkMemValue !== null &&
osType === OS_WINDOWS &&
dbVersion <= 17
) {
const winMemoryLimit =
(2 * SIZE_UNIT_MAP['GB']) / SIZE_UNIT_MAP['KB'] -
(1 * SIZE_UNIT_MAP['MB']) / SIZE_UNIT_MAP['KB']
if (autovacuumWorkMemValue > winMemoryLimit) {
autovacuumWorkMemValue = winMemoryLimit
}
}
return autovacuumWorkMemValue
}
function selectIoMethod(dbVersion, osType) {
// Asynchronous I/O was introduced in PostgreSQL 18
if (dbVersion < 18) {
return null
}
// If we assume standard modern packages (compiled with --with-liburing),
// io_uring is the absolute best performing AIO method for Linux.
if (osType === OS_LINUX) {
return 'io_uring'
}
// Windows and macOS do not support io_uring natively, so we fall back
// to the safe cross-platform 'worker' processes.
return 'worker'
}
function selectIoWorkers(dbVersion, cpuNum, ioMethod) {
// io_workers was introduced in PG18 for the new Asynchronous I/O subsystem
if (dbVersion < 18 || !cpuNum || ioMethod === 'io_uring') {
return null
}
// Default is 3. We conservatively scale it to ~25% of CPU cores to avoid
// lock contention on the AIO queue, capped at PostgreSQL's hard max of 32
const ioWorkersValue = Math.min(32, Math.max(3, Math.floor(cpuNum / 4)))
// Only explicitly configure it if we are recommending more than the default
return ioWorkersValue > 3 ? ioWorkersValue : null
}
function selectWarningInfoMessages(
totalMemory,
walCompression,
ioMethod,
dbType,
hdType,
dbSize,
) {
let warnings = []
// 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 (walCompression === 'lz4') {
if (warnings.length > 0) warnings.push('')
warnings.push(
'wal_compression = lz4 requires PostgreSQL',
'to be compiled with --with-lz4',
)
}
if (ioMethod === '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 (
dbType === DB_TYPE_DW &&
hdType !== HARD_DRIVE_HDD &&
dbSize !== 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] : []
}