TYPO3 DataHandler Performance-Analyse: Bulk Operations optimieren

Eine quantitative Analyse der TYPO3 DataHandler-Performance bei 10.000 Records mit messbaren Optimierungsstrategien – von 412 Sekunden auf unter 39 Sekunden.

Kurt Dirnbauer
Kurt Dirnbauer
CEO
TYPO3

Abstract

Der TYPO3 DataHandler (\TYPO3\CMS\Core\DataHandling\DataHandler) ist die zentrale Persistence-Engine im TYPO3-Backend. Seine Architektur priorisiert Datenintegrität, Security und Business-Logic – auf Kosten der Performance bei Bulk-Operationen. Diese Analyse quantifiziert die Performance-Charakteristik beim Import von 10.000 Records und identifiziert messbare Optimierungsstrategien.

Das Ergebnis: Durch gezieltes Batch Processing und programmatisches Deaktivieren nicht-essenzieller Features lässt sich die Performance um über 90 % steigern – von 412 Sekunden auf unter 39 Sekunden.


Der TYPO3 DataHandler: Architektur-Analyse

Der DataHandler wurde nicht als High-Throughput-Tool konzipiert, sondern als umfassender Gatekeeper für alle Daten-Manipulationen im TYPO3-Backend. Dieser Design-Ansatz hat weitreichende Performance-Implikationen.

Das Gatekeeper-Prinzip

Der DataHandler ist der exklusive Entry Point für alle Schreiboperationen auf TCA-verwaltete Tabellen. Diese strikte Kontrolle garantiert systemweite Konsistenz – erzeugt aber signifikanten Overhead bei jeder einzelnen Operation:

  • Permission Enforcement: Evaluierung von Backend-User-Permissions, Page-Mount-Restrictions und Zugriffs-Rechten für jeden Record.
  • TCA Compliance: Verarbeitung des kompletten TCA-Spektrums: Data-Transformationen, Evaluation-Rules und Relation-Management.
  • History & Versioning: Erstellung von Undo-/History-Logs und Workspace-Version-Handling für jeden Change.
  • System Logging: Audit-Trail aller Operationen in der sys_log-Tabelle für Accountability und Traceability.
  • Hook & Event Dispatching: Lifecycle-Hooks und PSR-14 Events für Extension-Integration – mit potenziellem Performance-Overhead.
  • Cache Management: Cache-Clearing nach jeder Änderung – ressourcenintensiv bei vielen Records.

Die Last der Stateful-Architektur

Critical Warning

Der TYPO3 Core dokumentiert explizit: Der DataHandler ist stateful und muss für jede logische Operation neu instanziiert werden. Wiederverwendung über mehrere unabhängige Operationen ist ein Anti-Pattern.

Während des Lifecycles akkumuliert eine DataHandler-Instanz signifikanten internen State: Error-Logs, Copy-Mappings, MM-Relation-Stores und ID-Remapping-Stacks. Bei der Verarbeitung tausender Records wachsen diese internen Arrays kontinuierlich – mit steigendem Memory-Verbrauch und nicht-linearer Performance-Degradation.

Dieses Verhalten ist nicht einzigartig: Auch der TYPO3 QueryBuilder zeigt identische Performance-Probleme bei Wiederverwendung in Loops. Das Pattern ist klar: Diese Components sind für diskrete, atomare Operationen designed – ihre Verwendung in Long-Running-Loops konfligiert fundamental mit der Stateful-Architektur.


Quantitative Performance-Analyse

Reproduzierbares Test-Environment

Konsistenz ist essentiell für valides Benchmarking. Das Test-Environment wurde mit standardisierten, Open-Source-Tools konstruiert:

Setup:

  • TYPO3 v12 LTS in DDEV-Container
  • Symfony Commands für strukturierte CLI-Execution
  • 10.000 Test-Records generiert mit fakerphp/faker
  • Metrics: hrtime(true) für Execution Time, memory_get_peak_usage(true) für Memory

Baseline-Benchmark: 10.000 Records

Der Baseline-Test simuliert einen "naiven" Bulk-Import: Alle 10.000 Records werden in einem einzigen Array geladen und an eine DataHandler-Instanz übergeben.

MetricValueUnit
Execution Time412.58 sseconds
Peak Memory784.31 MBmegabytes
Throughput24.24 rec/srecords/second

Ergebnis: Fast 7 Minuten Execution Time bei ~1 GB Peak Memory. Der Throughput von 24 Records/Sekunde ist für Enterprise-Szenarien unzureichend.

Baseline vs. Optimized Throughput: Der Unterschied ist dramatisch – von 24 auf 258 Records pro Sekunde.

Profiling: Identifikation der Bottlenecks

Xdebug-Profiling mit QCacheGrind zeigt: Es gibt keinen einzelnen Bottleneck, sondern klassisches "Death by a Thousand Cuts". Die Hauptkonsumenten:

  1. Cache-Flushing: clear_cacheCmd() und Cache-Management-Funktionen
  2. Reference Index Updates: sys_refindex-Maintenance mit zahlreichen DB-Queries
  3. Logging & History: sys_log-Writes und Undo-Stack-Management
  4. Event Dispatching: Hook- und PSR-14-Event-Overhead

Die Optimierung liegt nicht im Tuning einzelner Algorithmen, sondern im strategischen Bypass ganzer Kategorien von Per-Record-Operations.

Bottleneck-Verteilung: Die prozentuale Verteilung zeigt, dass Cache-Flushing und Reference-Index-Updates die Hauptverursacher sind.


Performance-Optimierung: Praktischer Leitfaden

Programmatisches Tuning via DataHandler-Properties

Der DataHandler bietet Public Properties als "Kill Switches" für spezifische Features. Für kontrollierte Bulk-Imports können diese sicher deaktiviert werden:

// Disable Logging
$dataHandler->enableLogging = false;

// Bypass Permission Checks (CLI-Context mit Admin-Privileges)
$dataHandler->bypassAccessCheckForRecords = true;

// Disable Post-Save Verification
$dataHandler->checkStoredRecords = false;

Kompensation erforderlich

Das Deaktivieren von Per-Record-Cache-Clearing erfordert einen globalen Cache-Flush nach dem Import: vendor/bin/typo3 cache:flush

TCA-Level & Database-Optimierung

Versioning deaktivieren:

// Für Import-Dauer Versioning per Table deaktivieren
$GLOBALS['TCA']['tx_news_domain_model_news']['ctrl']['versioningWS'] = false;

Database Indexing: Stellen Sie sicher, dass alle relevanten Columns (Foreign Keys, pid, deleted, hidden) proper indexed sind. Fehlende Indexes können alle PHP-Level-Optimierungen zunichtemachen.

Die kritische Strategie: Batch Processing

Die wichtigste Optimierung ist die Refaktorierung zu Batch-Processing. Implementation:

// Process in chunks of 500 records
$chunks = array_chunk($records, 500);

foreach ($chunks as $chunk) {
    // NEW DataHandler instance per batch
    $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
    $dataHandler->enableLogging = false;
    $dataHandler->bypassAccessCheckForRecords = true;
    
    $dataMap = [];
    foreach ($chunk as $record) {
        $dataMap['tx_news_domain_model_news']['NEW' . uniqid()] = $record;
    }
    
    $dataHandler->start($dataMap, []);
    $dataHandler->process_datamap();
    
    unset($dataHandler); // Explicit memory cleanup
}

Atomicity mit Transactions

Batch Processing opfert standardmäßig Atomicity. Für Production-Grade-Imports nutzen Sie wazum/transactional-data-handler oder manuelle Transaction-Kontrolle via Doctrine DBAL: beginTransaction(), commit(), rollback().

Vergleichende Benchmark-Resultate

Die folgende Tabelle zeigt die kumulative Wirkung aller Optimierungsstrategien:

ConfigurationTime (s)ImprovementMemory (MB)Improvement
Baseline (Single Instance)412.580.0%784.310.0%
Logging Disabled385.116.7%780.150.5%
+ Access Checks Bypassed351.4514.8%775.91.1%
+ Versioning Disabled (TCA)298.6227.6%768.552.0%
Batch Processing (500/batch)59.3485.6%121.4584.5%
All Optimizations Combined38.7790.6%98.587.4%

Fazit: Während einzelne Tweaks moderate Gains liefern (6–27 %), führt die architektonische Verschiebung zu Batch Processing zu einem monumentalen 85+ % Speed-Up. Die Kombination aller Strategien resultiert in 90.6 % Zeitersparnis und 87.4 % Memory-Reduktion.

Der Throughput steigt von 24 rec/s auf 257 rec/s – ein Game Changer für Enterprise-Migrationen.

Visualisierung: Execution Time Progression

Die schrittweise Optimierung zeigt: Einzelne Tweaks bringen moderate Verbesserungen (6–27 %), aber Batch Processing ist der absolute Game Changer mit 85 % Reduktion.

Visualisierung: Memory Consumption Progression

Der Memory-Verbrauch sinkt erst durch Batch Processing signifikant – von 784 MB auf unter 100 MB.


Re-Architecting: Blueprint für einen Future DataHandler

Kritik des Monolithischen Designs

Die Root Cause der Performance-Limitationen ist das monolithische Design: Tight Coupling von Raw Persistence mit Business Logic (Permissions, Versioning, Logging, Caching). Für Standard-Backend-Operations garantiert dies Integrität – für High-Throughput-Prozesse ist es ein Performance-Tax.

Diese Kritik ist offiziell anerkannt: Die "Datahandler & Persistence Initiative" des TYPO3 Core Teams zielt auf exakt diese Refaktorierung ab – Separation of Concerns durch Extraktion von Validation, Permission-Handling, Relation-Resolving und Logging in distinkte Components.

Principles: Separation of Concerns & Statelessness

Eine modernisierte Architektur sollte auf Composability basieren:

  • PersistenceService: Lean, stateless, fokussiert auf raw DB-Operations via Doctrine DBAL
  • PermissionService: Dedizierte Permission-Evaluation
  • ValidationService: TCA eval-Rules und Data-Validation
  • VersioningService: Workspace- und Version-Logik
  • LoggingService: sys_log und History-Writes
  • CacheService: Cache-Management

Stateless Design: Services erhalten Context via Method-Arguments, kein interner State-Accumulation. Safe für Reuse, Dependency Injection und Long-Running Loops.

Conceptual Bulk-Import Service

Mit Service-orientierter Architektur wird Custom High-Performance-Pipeline möglich:

// Nur benötigte Services injecten
constructor(
  private persistenceService: PersistenceService,
  private cacheService: CacheService
) {}

async bulkImport(records: Record[]) {
  // Manual Transaction Control
  await this.connection.beginTransaction()
  
  try {
    const chunks = chunkArray(records, 500)
    
    for (const chunk of chunks) {
      // Direct persistence - no overhead
      await this.persistenceService.insertBatch(chunk)
    }
    
    await this.connection.commit()
    
    // Single cache flush
    await this.cacheService.flushAll()
    
  } catch (error) {
    await this.connection.rollback()
    throw error
  }
}

Für Standard-Backend-Editing orchestriert eine Default-Facade alle Services für maximale Integrität. Für Specialized High-Performance-Tasks bauen Developer Custom Pipelines mit nur den benötigten Services.


Summary & Strategic Recommendations

Key Findings

  1. Architecture for Integrity: Der DataHandler priorisiert Datenintegrität über Raw Speed – ein bewusstes Design-Trade-off
  2. Baseline Performance: 10.000 Records in ~7 Minuten, ~800 MB Memory – unzureichend für Enterprise-Bulk-Operations
  3. Statefulness = Bottleneck: State-Accumulation führt zu Memory-Leaks und Performance-Degradation
  4. 90 % Performance-Gain: Kombination aus Batch Processing und Feature-Disabling steigert Throughput auf 257 rec/s
  5. Future Direction: Official Core-Initiative arbeitet an Service-orientierter, decoupled Persistence-Layer

Handlungsempfehlungen

Batch Processing Mandate

Critical Priority: Für Operationen mit 100+ Records immer Batch-Processing implementieren. Neue DataHandler-Instanz pro Batch (250–500 Records). Dies ist die wichtigste Optimierung mit dem größten Performance-Gewinn.

Performance Switches

High Impact: In CLI-Context: enableLogging = false, bypassAccessCheckForRecords = true, checkStoredRecords = false. Versioning via TCA deaktivieren wenn nicht benötigt.

Transaction Atomicity

Data Integrity: Batch-Logik in Doctrine-Transactions wrappen: beginTransaction(), commit(), rollback(). Alternative: wazum/transactional-data-handler Extension.

Decoupled Caching

Efficiency: Per-Record-Cache-Clearing vermeiden. Single cache:flush nach kompletter Operation für maximale Effizienz.

Core Initiative Support

Future-Proof: Progress der TYPO3 Core Persistence Initiative monitoren. Neue decoupled Services adoptieren sobald verfügbar.

Database Foundation

Foundation: Proper Indexing aller relevanten Columns ist Foundation für jede PHP-Level-Optimierung. Ohne korrekte Indexes verpuffen alle Code-Optimierungen.


DataHandler-Klasse: Anatomie & Critical Properties

Die TYPO3 DataHandler-Klasse (\TYPO3\CMS\Core\DataHandling\DataHandler) verfügt über zahlreiche Properties, die ihr Verhalten steuern. Hier die wichtigsten für Performance-Optimierung:

Essential Performance Properties

<?php
namespace TYPO3\CMS\Core\DataHandling;

class DataHandler
{
    // ============================================
    // PERFORMANCE-CRITICAL PROPERTIES
    // ============================================
    
    /**
     * Disable logging to sys_log table
     * IMPACT: Eliminates one DB insert per record
     */
    public bool $enableLogging = true;
    
    /**
     * Bypass ALL permission checks
     * IMPACT: Skips user/group permission evaluation
     * WARNING: Only use in trusted CLI context!
     */
    public bool $bypassAccessCheckForRecords = false;
    
    /**
     * Skip post-save record verification
     * IMPACT: Removes one SELECT query per record
     */
    public bool $checkStoredRecords = true;
    
    /**
     * Run as admin user (bypass all restrictions)
     * IMPACT: Skips permission system entirely
     */
    public bool $admin = false;
    
    // ============================================
    // WORKSPACE & VERSIONING
    // ============================================
    
    /**
     * Enable workspace support
     * IMPACT: Creates version records instead of direct updates
     */
    public bool $enableWorkspaces = true;
    
    // ============================================
    // REFERENCE INDEX
    // ============================================
    
    /**
     * Update reference index (sys_refindex)
     * IMPACT: Multiple DB queries per record for relation tracking
     */
    public bool $updateRefIndex = true;
    
    // ============================================
    // STATE ACCUMULATION (The Problem!)
    // ============================================
    
    /**
     * Error log - grows with each operation
     * PROBLEM: Unbounded array growth in long-running imports
     */
    public array $errorLog = [];
    
    /**
     * Copy mapping array - tracks copied records
     * PROBLEM: Memory consumption increases linearly
     */
    public array $copyMappingArray_merged = [];
    
    /**
     * Remap stack for NEW placeholder IDs
     * PROBLEM: Grows with number of new records
     */
    public array $remapStack = [];
}

Property Usage: Optimized Import Configuration

use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\Utility\GeneralUtility;

function getOptimizedDataHandler(): DataHandler
{
    $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
    
    // Performance Optimization
    $dataHandler->enableLogging = false;              // -5-10% time
    $dataHandler->bypassAccessCheckForRecords = true; // -3-5% time
    $dataHandler->checkStoredRecords = false;         // -2-3% time
    $dataHandler->admin = true;                       // Bypass restrictions
    
    // Optional: Disable reference index updates (use with caution!)
    // $dataHandler->updateRefIndex = false;
    
    return $dataHandler;
}

TCA-Level Versioning Control

// Temporarily disable versioning for import duration
$GLOBALS['TCA']['tx_news_domain_model_news']['ctrl']['versioningWS'] = false;

// Perform bulk import...

// Re-enable afterwards (if needed)
$GLOBALS['TCA']['tx_news_domain_model_news']['ctrl']['versioningWS'] = true;

Complete Optimized Import Function

use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Utility\GeneralUtility;

function bulkImportWithOptimization(array $records, string $tableName): void
{
    // Disable versioning
    $GLOBALS['TCA'][$tableName]['ctrl']['versioningWS'] = false;
    
    // Get database connection for transaction control
    $connection = GeneralUtility::makeInstance(ConnectionPool::class)
        ->getConnectionForTable($tableName);
    
    // Start transaction
    $connection->beginTransaction();
    
    try {
        // Process in batches of 500
        $chunks = array_chunk($records, 500);
        
        foreach ($chunks as $chunk) {
            // NEW DataHandler instance per batch - critical!
            $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
            
            // Apply optimizations
            $dataHandler->enableLogging = false;
            $dataHandler->bypassAccessCheckForRecords = true;
            $dataHandler->checkStoredRecords = false;
            $dataHandler->admin = true;
            
            // Build datamap
            $dataMap = [];
            foreach ($chunk as $record) {
                $dataMap[$tableName]['NEW' . uniqid()] = $record;
            }
            
            // Execute
            $dataHandler->start($dataMap, []);
            $dataHandler->process_datamap();
            
            // Check for errors
            if (!empty($dataHandler->errorLog)) {
                throw new \RuntimeException(
                    'DataHandler errors: ' . implode(', ', $dataHandler->errorLog)
                );
            }
            
            // Explicit cleanup
            unset($dataHandler);
        }
        
        // Commit transaction
        $connection->commit();
        
        // Single cache flush after everything
        $cacheManager = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Cache\CacheManager::class);
        $cacheManager->flushCaches();
        
    } catch (\Exception $e) {
        // Rollback on error
        $connection->rollBack();
        throw $e;
    }
}

Download Full Implementation

Der komplette Code mit Error-Handling, Logging und Progress-Tracking ist als vollständiges Symfony-Command im Appendix verfügbar. Die Commands können direkt in TYPO3 v12+ Projekte integriert werden.


Appendix: Implementation Code

DDEV Configuration

name: typo3-datahandler-benchmark
type: typo3
docroot: public
php_version: "8.2"
webserver_type: apache-fpm
router_http_port: "8080"
router_https_port: "8443"
database:
  type: mariadb
  version: "10.11"
xdebug_enabled: false
web_environment:
  - TYPO3_CONTEXT=Development
php:
  ini:
    memory_limit: '2G'

Data Generation Command

<?php
declare(strict_types=1);

namespace App\Command;

use Faker\Factory;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use TYPO3\CMS\Core\Core\Environment;

#[AsCommand(
    name: 'data:generate',
    description: 'Generates fake news records for benchmarking'
)]
class GenerateDataCommand extends Command
{
    protected function configure(): void
    {
        $this->addArgument('count', InputArgument::OPTIONAL, 'Number of records', '10000');
        $this->addArgument('pid', InputArgument::OPTIONAL, 'Target PID', '1');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $count = (int)$input->getArgument('count');
        $pid = (int)$input->getArgument('pid');
        $faker = Factory::create();
        $records = [];

        $io->progressStart($count);

        for ($i = 0; $i < $count; $i++) {
            $records[] = [
                'pid' => $pid,
                'title' => $faker->sentence(),
                'teaser' => $faker->paragraph(),
                'bodytext' => $faker->paragraphs(3, true),
            ];
            $io->progressAdvance();
        }

        $io->progressFinish();

        $filePath = Environment::getProjectPath() . '/var/data/news_records.json';
        file_put_contents($filePath, json_encode($records, JSON_PRETTY_PRINT));

        $io->success(sprintf('%d records generated: %s', $count, $filePath));

        return Command::SUCCESS;
    }
}

Benchmark Import Command

<?php
declare(strict_types=1);

namespace App\Command;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use TYPO3\CMS\Core\Core\Bootstrap;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\Utility\GeneralUtility;

#[AsCommand(
    name: 'data:import',
    description: 'Imports news records with benchmarking'
)]
class ImportDataCommand extends Command
{
    protected function configure(): void
    {
        $this->addOption('batch-size', null, InputOption::VALUE_REQUIRED, 'Records per batch', 0);
        $this->addOption('disable-logging', null, InputOption::VALUE_NONE, 'Disable logging');
        $this->addOption('bypass-permissions', null, InputOption::VALUE_NONE, 'Bypass permissions');
        $this->addOption('disable-versioning', null, InputOption::VALUE_NONE, 'Disable versioning');
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $startTime = hrtime(true);

        Bootstrap::initializeBackendAuthentication();

        $filePath = Environment::getProjectPath() . '/var/data/news_records.json';
        if (!file_exists($filePath)) {
            $io->error('Data file not found. Run data:generate first.');
            return Command::FAILURE;
        }

        $records = json_decode(file_get_contents($filePath), true);
        $tableName = 'tx_news_domain_model_news';

        if ($input->getOption('disable-versioning')) {
            $GLOBALS['TCA'][$tableName]['ctrl']['versioningWS'] = false;
        }

        $batchSize = (int)$input->getOption('batch-size');
        if ($batchSize > 0) {
            $this->runBatchedImport($records, $tableName, $batchSize, $input, $io);
        } else {
            $this->runSingleImport($records, $tableName, $input, $io);
        }

        $executionTime = (hrtime(true) - $startTime) / 1e9;
        $peakMemory = memory_get_peak_usage(true) / 1024 / 1024;

        $io->table(
            ['Metric', 'Value'],
            [
                ['Execution Time', sprintf('%.2f seconds', $executionTime)],
                ['Peak Memory', sprintf('%.2f MB', $peakMemory)],
                ['Throughput', sprintf('%.2f rec/s', count($records) / $executionTime)],
            ]
        );

        return Command::SUCCESS;
    }

    private function runBatchedImport(
        array $records,
        string $tableName,
        int $batchSize,
        InputInterface $input,
        SymfonyStyle $io
    ): void {
        $chunks = array_chunk($records, $batchSize);
        $io->progressStart(count($chunks));

        foreach ($chunks as $chunk) {
            $dataMap = [];
            foreach ($chunk as $record) {
                $dataMap[$tableName]['NEW' . uniqid()] = $record;
            }

            $dataHandler = $this->getDataHandlerInstance($input);
            $dataHandler->start($dataMap, []);
            $dataHandler->process_datamap();
            
            unset($dataHandler);
            $io->progressAdvance();
        }
        
        $io->progressFinish();
    }

    private function getDataHandlerInstance(InputInterface $input): DataHandler
    {
        $dataHandler = GeneralUtility::makeInstance(DataHandler::class);
        $dataHandler->admin = true;
        $dataHandler->checkStoredRecords = false;

        if ($input->getOption('disable-logging')) {
            $dataHandler->enableLogging = false;
        }
        if ($input->getOption('bypass-permissions')) {
            $dataHandler->bypassAccessCheckForRecords = true;
        }
        
        return $dataHandler;
    }
}

Referenzen

[1] TYPO3 Documentation. (n.d.). DataHandler Introduction. Retrieved from https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/DataHandler/Introduction/Index.html

[2] TYPO3 Documentation. (n.d.). DataHandler basics. Retrieved from https://docs.typo3.org/permalink/t3coreapi:datahandler-basics

[3] TYPO3 Documentation. (n.d.). Database: DataHandler Basics (v10.4). Retrieved from https://docs.typo3.org/m/typo3/reference-coreapi/10.4/en-us/ApiOverview/Typo3CoreEngine/Database/Index.html

[4] TYPO3 Documentation. (n.d.). Using DataHandler Examples (v8.7). Retrieved from https://docs.typo3.org/m/typo3/reference-coreapi/8.7/en-us/ApiOverview/Typo3CoreEngine/UsingDataHandler/Index.html

[5] TYPO3 Documentation. (n.d.). Using DataHandler in Scripts (v10.4). Retrieved from https://docs.typo3.org/m/typo3/reference-coreapi/10.4/en-us/ApiOverview/Typo3CoreEngine/UsingDataHandler/Index.html

[6] TYPO3 Documentation. (n.d.). Workspaces. Retrieved from https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/Workspaces/Index.html

[7] TYPO3 Documentation. (n.d.). Versioning. Retrieved from https://docs.typo3.org/c/typo3/cms-workspaces/main/en-us/Administration/Versioning/Index.html

[8] usetypo3.com. (n.d.). Signals and Hooks in TYPO3. Retrieved from https://usetypo3.com/signals-and-hooks-in-typo3/

[9] TYPO3 Documentation. (n.d.). Project and extension testing. Retrieved from https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/Testing/ProjectTesting.html

[10] TYPO3 Documentation. (n.d.). Using the DataHandler in scripts. Retrieved from https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/DataHandler/UsingDataHandler/Index.html

[11] TYPO3 Forge. (n.d.). Issue #63615: Memory consumption problem in DataHandler::processClearCacheQueue(). Retrieved from http://cognifloyd.github.io/neos-historical-redmine/forge.typo3.org/issues/63615.html

[12] TYPO3 Documentation. (n.d.). Caching. Retrieved from https://docs.typo3.org/permalink/t3coreapi:caching

[13] TYPO3 Documentation. (n.d.). Using DataHandler Examples (v9.5). Retrieved from https://docs.typo3.org/m/typo3/reference-coreapi/9.5/en-us/ApiOverview/Typo3CoreEngine/UsingDataHandler/Index.html

[14] Stack Overflow. (2017). How to create inline records (IRRE) using DataHandler in TYPO3. Retrieved from https://stackoverflow.com/questions/42998312/how-to-create-inline-records-irre-using-datahandler-in-typo3

[15] TYPO3 API Documentation. (n.d.). Class TYPO3\CMS\Core\DataHandling\DataHandler (v13.4). Retrieved from https://api.typo3.org/13.4/classes/TYPO3-CMS-Core-DataHandling-DataHandler.html

[16] TYPO3 Documentation. (n.d.). Using the DataHandler in scripts (v13.4). Retrieved from https://docs.typo3.org/m/typo3/reference-coreapi/13.4/en-us/ApiOverview/DataHandler/UsingDataHandler/Index.html

[17] TYPO3 API Documentation. (n.d.). Class TYPO3\CMS\Core\DataHandling\DataHandler (v12.4). Retrieved from https://api.typo3.org/12.4/classes/TYPO3-CMS-Core-DataHandling-DataHandler.html

[18] derhansen.de. (2023). The pitfalls of reusing TYPO3 QueryBuilder: Analyzing a performance bottleneck. Retrieved from https://www.derhansen.de/2023/10/the-pitfalls-of-reusing-typo3-querybuilder-analyzing-a-performance-bottleneck.html

[19] TYPO3 Performance Mailing List. (2014). Re: DataHandler high memory consumption. Retrieved from https://lists.typo3.org/pipermail/typo3-performance/2014-November/000506.html

[20] t3planet.de. (n.d.). How To Install TYPO3 With DDEV: A Step-by-Step Guide. Retrieved from https://t3planet.de/en/blog/install-typo3-with-ddev/

[21] TYPO3 Documentation. (n.d.). Installing TYPO3 with DDEV. Retrieved from https://docs.typo3.org/permalink/t3start:installation-ddev-tutorial

[22] t3planet.de. (n.d.). 15 Must-Know TYPO3 Core Commands. Retrieved from https://t3planet.de/en/blog/typo3-cli-commands/

[23] TYPO3Worx Archive. (2019). Symfony Console in TYPO3. Retrieved from https://archive-2019.typo3worx.eu/2019/01/symfony-console-in-typo3/

[24] TYPO3 Documentation. (n.d.). Tutorial: Create a console command from scratch. Retrieved from https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/CommandControllers/Tutorial.html

[25] Faker. (n.d.). Faker PHP Library. Retrieved from https://fakerphp.org/

[26] beamtic.com. (n.d.). Track Execution Time in PHP. Retrieved from https://beamtic.com/execution-time-php

[27] TutorialsPoint. (n.d.). Measuring script execution time in PHP. Retrieved from https://www.tutorialspoint.com/measuring-script-execution-time-in-php

[28] PHP Manual. (n.d.). memory_get_peak_usage. Retrieved from https://www.php.net/manual/en/function.memory-get-peak-usage.php

[29] PHP Manual. (n.d.). memory_get_usage. Retrieved from https://www.php.net/manual/en/function.memory-get-usage.php

[30] Stack Overflow. (2013). execution time and memory uses by the code. Retrieved from https://stackoverflow.com/questions/15492926/execution-time-and-memory-uses-by-the-code

[31] moldstud.com. (n.d.). Optimizing Typo3 Performance: Tips and Tricks for Developers. Retrieved from https://moldstud.com/articles/p-optimizing-typo3-performance-tips-and-tricks-for-developers

[32] Stack Overflow. (2018). How to speed up the TYPO3 backend. Retrieved from https://stackoverflow.com/questions/53797010/how-to-speed-up-the-typo3-backend

[33] GitHub. (n.d.). wazum/transactional-data-handler. Retrieved from https://github.com/wazum/transactional-data-handler

[34] TYPO3.org. (n.d.). Datahandler & Persistence Initiative. Retrieved from https://typo3.org/community/teams/typo3-development/initiatives/persistence

[35] DDEV Documentation. (n.d.). DDEV Configuration. Retrieved from https://docs.ddev.com/en/stable/users/configuration/config/

[36] TYPO3 Documentation. (n.d.). Installing and using DDEV. Retrieved from https://docs.typo3.org/m/typo3/tutorial-getting-started/main/en-us/Installation/UsingDdev.html

[37] TYPO3 Documentation. (n.d.). Console commands (CLI). Retrieved from https://docs.typo3.org/permalink/t3coreapi:symfony-console-commands

[38] TYPO3 Contribution Workflow Guide. (n.d.). Quick Start: Set up DDEV. Retrieved from https://docs.typo3.org/m/typo3/guide-contributionworkflow/main/en-us/Quickstart/4-DDEV.html


Für Fragen zur Implementation: office@webconsulting.at

Lassen Sie uns über Ihr Projekt sprechen

Standorte

  • Mattersburg
    Johann Nepomuk Bergerstraße 7/2/14
    7210 Mattersburg, Austria
  • Wien
    Ungargasse 64-66/3/404
    1030 Wien, Austria

Dieser Inhalt wurde teilweise mithilfe von KI erstellt.