I SQL fungerer markører som en pointer, der gør det muligt for applikationsprogrammeringssprog at håndtere forespørgselsresultater en række ad gangen. Denne artikel udforsker hurtigt konceptet bag og viser, hvordan man angiver markører, åbner, henter data fra dem og derefter lukker dem.
SQL-markører
Dataene i relationsdatabasen styres i form af sæt. Som et resultat heraf omtales forespørgselsresultater, der returneres af SQL SELECT-sætninger, som resultatsæt. Resultatsættene er intet andet end kombinationer af en eller flere rækker og kolonner udtrukket fra en eller flere tabeller. Du kan rulle gennem resultatsættene for at udtrække de oplysninger, du har brug for. De returnerede dataelementer bruges af programmeringssprog som Java eller andre til specifikke applikationsformål. Men her ligger problemet med impedansmismatch på grund af forskellen i konstruktion mellem databasemodel og programmeringssprogsmodel.
En SQL-databasemodel har tre hovedkonstruktioner:
- kolonner (eller attributter) og deres datatyper
- rækker (poster eller tupler)
- tabeller (samling af poster)
Derfor er det primære misforhold mellem to modeller:
- De tilgængelige attributdatatyper i databasemodellen er ikke de samme som de variabeltyper, der bruges i programmeringssprog. Der er mange værtssprog, og hver har en anden datatype. For eksempel er datatyperne C/C++ og Java forskellige, og det samme er SQL-datatyper. Derfor er en bindende mekanisme nødvendig for at afhjælpe inkompatibilitetsproblemet.
- Resultatet returneret af SQL SELECT-sætninger er multi-sæt af poster, hvor hver post er en samling af attributter. Værtsprogrammeringssprog fungerer typisk på individuelle dataværdier for tuple, der returneres af forespørgslen. Derfor er det essentielt, at SQL-forespørgselsresultater afbildes med den datastruktur, der understøttes af programmeringssproget. Mekanismen for løkke over tupler er nødvendig for at iterere over tupler og deres attributværdier.
Markøren fungerer som en iteratorvariabel til at sløjfe over tupler, der returneres af SQL-forespørgslen, og udtrække individuelle værdier inden for hver tuple, som derefter kan tilknyttes passende type programvariabler.
Markøren fungerer derfor som en markør, der gør det muligt for programmeringssproget at behandle forespørgselsresultatet én post ad gangen. En markør kan bevæge sig gennem alle rækker af et forespørgselsresultat med fokus på én række ad gangen. Overvej følgende SQL-forespørgsel:
SELECT emp_no, first_name, last_name, birth_date FROM employees WHERE MONTH(birth_date) = MONTH(CURRENT_DATE) AND DAY(birth_date) = DAY(CURRENT_DATE);
Forespørgselsresultatet fra ovenstående erklæring returnerer medarbejderoplysninger for alle de medarbejdere, hvis fødselsdato falder på den aktuelle dag i en bestemt måned. Resultatet kan indeholde mange rækker, men værtsapplikationssproget kan håndtere en række ad gangen. Som et resultat erklæres markøren som en indlejret SQL-sætning i applikationsprogrammeringssproget. Markøren åbnes derefter meget som en fil og udtræk en enkelt række fra forespørgselsresultatet. Andre rækker udtrækkes efterfølgende, i rækkefølge, indtil markøren lukkes.
Erklæring af en markør
Markører erklæres meget som en variabel. Der gives et navn, der er sætninger til at åbne markøren, hente forespørgselsresultatet og til sidst lukke markøren. Bemærk, at forskellige SQL-implementeringer understøtter brugen af markører på en anden måde. Men der er en generel enighed om, hvordan markøren skal skrives.
Vi skal bruge SQL-sætninger til fuldt ud at implementere markørfunktionalitet, fordi blot at erklære en markør ikke er nok til at udtrække data fra en SQL-database. Der er fire grundlæggende trin til at erklære en markør:
ERKLÆR MARKØR: Erklæringen begynder med at give markøren et navn og tildele det forespørgselsudtryk, der skal fremkaldes, når markøren åbnes.
ÅBEN: Open-sætningen udfører det tildelte forespørgselsudtryk og gør forespørgselsresultatet klar til efterfølgende FETCH.
HENT: Henter dataværdier til variabler, som derefter kan overføres til værtsprogrammeringssproget eller til andre indlejrede SQL-sætninger.
LUK: Markøren er lukket for at hente flere forespørgselsresultater.
Syntaksen er som følger:
DECLARE <cursor_name> [SENSITIVE | INSENSITIVE | ASENSITIVE] [SCROLL | NO SCROLL] CURSOR [ WITH HOLD | WITHOUT HOLD] [ WITH RETURN | WITHOUT RETURN] FOR <sql_query_expression> [ ORDER BY <sort_expression>] [ FOR {READ ONLY | UPDATE [ OF <list_of_column>]}]
Den væsentlige del af en markørerklæring er som følger:
DECLARE <cursor_name> FOR <sql_query_expression>
Den valgfri del såsom [SENSITIVE | INSENSITIV | ASENSITIVE] angiver, om markøren er følsom over for ændringer, og om de skal afspejles i forespørgselsresultatet. SENSITIV betyder, at markøren er påvirket af ændringer, INSENSITIV betyder, at markøren ikke er påvirket, og ASENSITIV betyder, at ændringer kan eller måske ikke er synlige for markøren. Hvis det ikke er angivet, antager det ASENSITIVE valgmulighed.
Den valgfrie [SCROLL | NOSCROLL] definerer cursorens rulleevne. Hvis det ikke er angivet, antager det NO SCROLL-indstillingen.
Den valgfrie [ MED HOLD | WITHOUT HOLD] definerer, om der skal holdes eller automatisk lukkes, når transaktionen på grund af markøren er begået. Hvis det ikke er angivet, bevarer den muligheden UDEN HOLD.
Den valgfrie [ MED RETURNERING | WITHOUT RETURN] bestemmer, om markørresultatsættet skal returneres til invokeren, såsom en anden SQL-rutine eller værtssprog. Hvis det ikke er angivet, betyder det UDEN RETURNERING.
ORDER BY-klausulen bruges til at sortere det returnerede forespørgselsresultat i henhold til den specificerede sorteringsteknik.
UPDATE-indstillingen refererer til brugen af UPDATE- eller DELETE-sætningen er forbundet med rækkerne, der returneres af markørens SELECT-sætning. Enhver sådan ændring er ikke mulig, hvis vi angiver muligheden LÆSEKUN. Hvis det ikke er angivet, antages det som standard OPDATERING.
Derfor kan en simpel markør erklæres som følger:
DECLARE mycursor CURSOR FOR SELECT emp_no, first_name, last_name, birth_date FROM employees WHERE MONTH(birth_date) = MONTH(CURRENT_DATE) AND DAY(birth_date) = DAY(CURRENT_DATE);
Markører i MySQL
Typisk findes der to typer markører i MySQL:skrivebeskyttede og kun fremadrettede markører. Disse markører kan bruges til MySQL-lagrede procedurer. Disse markører hjælper os med at iterere over forespørgselsresultater én række ad gangen og hente ind i variabler til yderligere behandling. Det er muligt at erklære mere end én markør og indlejre dem i sløjfer. Bemærk, at markører er skrivebeskyttede, fordi de bruges til at iterere over midlertidige tabeller. Markøren udfører typisk forespørgslen, mens vi åbner den.
Et af problemerne med markøren i MySQL er, at de kan sænke ydelsen af forespørgslen på grund af ekstra I/O-operationer, de udfører. Dette er især for ægte store datatyper såsom BLOB og TEXT. Da markører arbejder med midlertidige tabeller, understøttes disse typer ikke i tabeller i hukommelsen. Derfor, mens jeg arbejder med disse typer, skal MySQL oprette midlertidige tabeller på disken, og det kræver en masse I/O-drift og det også i langsomme enheder som diske. Dette er den primære årsag til langsom ydeevne af markøren.
MySQL understøtter heller ikke markører på klientsiden, men klient-API'en kan efterligne dem, hvis det er nødvendigt. Men så er dette ikke meget anderledes end at hente resultatet i et array i programmeringssprog som Java og manipulere dem der i stedet.
Her er et eksempel på, hvordan man skriver markører i MySQL.
CREATE PROCEDURE 'cursor_demo'() BEGIN DECLARE done INT DEFAULT FALSE; DECLARE id INT(11); DECLARE fn varchar(14); DECLARE ln varchar(16); DECLARE bdate date; DECLARE mycursor CURSOR FOR SELECT emp_no, first_name, last_name, birth_date FROM employees WHERE MONTH(birth_date)=MONTH(CURRENT_DATE) AND DAY(birth_date)=DAY(CURRENT_DATE); DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; OPEN mycursor; fetch_loop: LOOP FETCH mycursor INTO id, fn, ln, bdate; IF done THEN LEAVE fetch_loop; END IF; SELECT id, fn, ln, bdate; END LOOP; CLOSE mycursor; END
Kald den er lagrede procedure som følger:
mysql> CALL cursor_demo
Proceduren henter rækkerne fra en tabel med navnet medarbejder hvis fødselsdato matcher den aktuelle dag og måned i en markør ved navn mycursor og udskriver dem simpelthen ved hjælp af SELECT-sætning.
Se MySQL-dokumentationen på markøren for mere information.
Konklusion
Markører er intet andet end pejlemærker til de rekordsæt, der returneres af SQL-forespørgsel. Markøren peger typisk på en række ad gangen og kan gennemløbes i en løkke for at hente individuelle poster. SQL bruges normalt til direkte opkald for at få adgang til og oprette dataobjekter. Markørerne giver teknikken til interaktiv SQL, hvor den muliggør ad hoc-udførelse af SQL-sætninger lettet gennem klientapplikation. Markørens mekanisme udnytter dataadgangsmodellen, hvor SQL-sætninger er indlejret i værtssprog såsom C, C++ eller Java osv. Dette er blot et glimt af, hvad cursor handler om til at begynde med. Se den relevante SQL-databasedokumentation for detaljer om specifikke normer for forskellige implementeringer.
# # #