sql >> Database >  >> RDS >> PostgreSQL

Waarom roept PostgreSQL mijn STABLE/IMMUTABLE-functie meerdere keren aan?

De volgende uitbreiding van uw testcode is informatief:

CREATE OR REPLACE FUNCTION test_multi_calls1(one integer)
RETURNS integer
AS $BODY$
BEGIN
    RAISE NOTICE 'Immutable called with %', one;
    RETURN one;
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION test_multi_calls2(one integer)
RETURNS integer
AS $BODY$
BEGIN
    RAISE NOTICE 'Volatile called with %', one;
    RETURN one;
END;
$BODY$ LANGUAGE plpgsql VOLATILE;

WITH data AS
(
    SELECT 10 AS num
    UNION ALL SELECT 10
    UNION ALL SELECT 20
)
SELECT test_multi_calls1(num)
FROM data
where test_multi_calls2(40) = 40
and test_multi_calls1(30) = 30

UITGANG:

NOTICE:  Immutable called with 30
NOTICE:  Volatile called with 40
NOTICE:  Immutable called with 10
NOTICE:  Volatile called with 40
NOTICE:  Immutable called with 10
NOTICE:  Volatile called with 40
NOTICE:  Immutable called with 20

Hier kunnen we zien dat terwijl in de select-lijst de onveranderlijke functie meerdere keren werd aangeroepen, in de waar-clausule het eenmaal werd aangeroepen, terwijl de vluchtige functie driemaal werd aangeroepen.

Het belangrijkste is niet dat PostgreSQL alleen een STABLE aanroept of IMMUTABLE functie eenmaal met dezelfde gegevens - uw voorbeeld laat duidelijk zien dat dit niet het geval is - het is dat het mogelijk noem het maar een keer. Of misschien roept hij het twee keer aan terwijl het 50 keer een vluchtige versie zou moeten aanroepen, enzovoort.

Er zijn verschillende manieren waarop gebruik kan worden gemaakt van stabiliteit en onveranderlijkheid, met verschillende kosten en baten. Om het soort besparing te bieden dat u voorstelt, zou het moeten maken met selectielijsten, het zou de resultaten in de cache moeten opslaan en vervolgens elk argument (of lijst met argumenten) in deze cache moeten opzoeken voordat het in de cache opgeslagen resultaat wordt geretourneerd of de functie in een cache wordt aangeroepen -missen. Dit zou duurder zijn dan het aanroepen van uw functie, zelfs in het geval dat er een hoog percentage cache-hits was (er zou 0% cache-hits kunnen zijn, wat betekent dat deze "optimalisatie" extra werk deed zonder enige winst). Het zou misschien alleen de laatste parameter en het resultaat kunnen opslaan, maar nogmaals, dat zou volledig nutteloos kunnen zijn.

Dit is vooral het geval als je bedenkt dat stabiele en onveranderlijke functies vaak de lichtste functies zijn.

Met de waar-clausule echter, de onveranderlijkheid van test_multi_calls1 stelt PostgreSQL in staat om de query daadwerkelijk te herstructureren vanuit de duidelijke betekenis van de gegeven SQL:

Naar een geheel ander zoekplan:

Dit is het soort gebruik dat PostgreSQL maakt van STABLE en IMMUTABLE - niet het cachen van resultaten, maar het herschrijven van query's in verschillende query's die efficiënter zijn maar dezelfde resultaten opleveren.

Merk ook op dat test_multi_calls1(30) vóór test_multi_calls2(40) wordt aangeroepen, ongeacht in welke volgorde ze in de where-clausule verschijnen. Dit betekent dat als de eerste aanroep ertoe leidt dat er geen rijen worden geretourneerd (vervang = 30 met = 31 om te testen) dan wordt de vluchtige functie helemaal niet aangeroepen - opnieuw ongeacht aan welke kant van de and .

Dit specifieke soort herschrijven hangt af van onveranderlijkheid of stabiliteit. Met where test_multi_calls1(30) != num het herschrijven van query's vindt plaats voor onveranderlijke, maar niet alleen voor stabiele functies. Met where test_multi_calls1(num) != 30 het zal helemaal niet gebeuren (meerdere oproepen) hoewel er andere optimalisaties mogelijk zijn:

Expressies die alleen de functies STABLE en IMMUTABLE bevatten, kunnen worden gebruikt met indexscans. Expressies die VOLATILE-functies bevatten, kunnen dat niet. Het aantal calls kan wel of niet afnemen, maar veel belangrijker is dat de resultaten van de calls dan op een veel efficiëntere manier worden gebruikt in de rest van de query (alleen echt van belang bij grote tabellen, maar dan kan het een enorme verschil).

Denk in het algemeen niet aan vluchtigheidscategorieën in termen van geheugenopslag, maar eerder in termen van het geven van de queryplanner van PostgreSQL om volledige zoekopdrachten te herstructureren op manieren die logisch equivalent zijn (dezelfde resultaten) maar veel efficiënter.



  1. CSV opslaan met UTF-16BE-codering in PHP

  2. Slaapstand:wat is het verschil tussen MySQLDialect en MySQLInnoDBDialect?

  3. MySQL-query om het eerste woord uit een veld te extraheren

  4. Hoe u Change Data Capture (CDC) op een database in SQL Server inschakelt - SQL Server-zelfstudie