{"id":194,"date":"2012-10-31T08:35:03","date_gmt":"2012-10-31T07:35:03","guid":{"rendered":"http:\/\/blog.systemconnect.dk\/?p=194"},"modified":"2015-04-25T14:12:50","modified_gmt":"2015-04-25T12:12:50","slug":"sql-vs-native-med-et-tvist-af-en-indbygget-sql-bug","status":"publish","type":"post","link":"https:\/\/scblog.lynge.org\/?p=194","title":{"rendered":"SQL vs Native &#8211; med et tvist af en indbygget SQL-bug?"},"content":{"rendered":"<p>Som regel kan en C5 p\u00e5 Native-databasen umiddelbart skiftes til SQL-databasen, hvis man \u00f8nsker det&#8230; Og det uden problemer af nogen art&#8230;<\/p>\n<p>Det kr\u00e6ver naturligvis at is\u00e6r RecID-pegere er angivet korrekt i databasen med referencefelter til enten den korrekte tabels RecID-felt, eller til Common-tabellens RecID. Men det er mere for at kunne lave data-export\/-import, s\u00e5 det er ikke specifikt for SQL.<\/p>\n<p>I selve applikationskoden er der ingen problemer med den medf\u00f8lgende applikation, MEN der kan naturligvis v\u00e6re ufordringer og muligheder for at optimere koden til at tage h\u00f8jde for at den nu afvikles p\u00e5 SQL.<\/p>\n<p>Kort fortalt er det en rigtig god id\u00e9 at s\u00e6tte sig ind og bruge\u00a0#USING-makroen (n\u00e5r man er ligeglad med resultatets sortering)\u00a0og\u00a0SQL-optimerings-makroerne, mere specifikt:<\/p>\n<ul>\n<li>#SQLFieldList<\/li>\n<li>#SQLSumList<\/li>\n<li>#SQLCountList<\/li>\n<li>#SQLMinList<\/li>\n<li>#SQLMaxList<\/li>\n<\/ul>\n<p>Du kan l\u00e6se mere om disse i dette indl\u00e6g: <a title=\"SQL-kode p\u00e5 speed?\" href=\"http:\/\/blog.systemconnect.dk\/?p=204\">SQL-kode p\u00e5 speed?<\/a><\/p>\n<p>F\u00e6lles for kaldene er at de enten aflaster SQL-serveren (#USING), eller &#8220;skubber&#8221; mere afvikling ud til SQL-serveren s\u00e5 klienten &#8220;spares&#8221; for det. Og det giver hurtigere afvikling og bedre samtidighed (bedre oplevelse en r\u00e6kke brugere f\u00e5r n\u00e5r de k\u00f8rer ting i C5 samtidigt).<\/p>\n<p>Faktisk b\u00f8r disse optimeringskald ALTID bruges &#8211; ogs\u00e5 hvis man udvikler til Native. P\u00e5 Native g\u00f8r det blot ingenting og det fremtidssikrer\u00a0din kode til SQL&#8230; S\u00e5 i bund og grund er det en vane-sag&#8230;<\/p>\n<p>I \u00f8vrigt b\u00f8r man undg\u00e5 konstruktioner i stil med:<\/p>\n<pre>INTRODUCE Notes[NotesIdx, &amp;NotesFileId, &amp;NotesRecId, &amp;NotesLineNo]\r\nSET Notes.Txt = 'TEST'\r\nINSERT Notes\r\n\r\n<\/pre>\n<p>&#8230;dvs. alts\u00e5 at udnytte at opslags-syntaxen p\u00e5 INTRODUCE faktisk s\u00e6tter de felter opslaget laves p\u00e5, n\u00e5r man alligevel blot laver en INSERT.<\/p>\n<p>For det f\u00f8rste er det ikke s\u00e5 let at l\u00e6se hvis man ikke er erfaren udvikler\u00a0&#8211; og for det andet koster det faktisk b\u00e5de et opslag (SEARCH) i databasen\u00a0og s\u00e5 naturligvis en INSERT. I stedet b\u00f8r man ganske simpelt n\u00f8jes med INTRODUCE uden opslag og s\u00e5 selv s\u00e6tte felterne:<\/p>\n<pre>INTRODUCE Notes\r\nSET Notes.NotesFileId = &amp;NotesFileId\r\nSET Notes.NotesRecID = &amp;NotesRecID\r\nSET Notes.LineNumber = &amp;NotesLineNo\r\nSET Notes.Txt = 'TEST'\r\nINSERT Notes\r\n\r\n<\/pre>\n<p>Det er naturligvis ogs\u00e5 det samme p\u00e5 b\u00e5de SQL og Native, om end en SEARCH p\u00e5 SQL er tungere (den skal jo typisk sendes over netv\u00e6rket\u00a0fra klienten til serveren og svaret skal sendes retur).<\/p>\n<p>NB: Microsoft har udgivet et ganske godt White Paper der gennemg\u00e5r ovenst\u00e5ende &#8211; og flere ting. Det kan anbefales at l\u00e6se dette hvis man udvikler mod C5 p\u00e5 SQL eller blot skriver kode som kan t\u00e6nkes at havne p\u00e5 SQL en dag&#8230;<\/p>\n<p>Men hvad s\u00e5 &#8211; er der f\u00e6lder indbygget i SQL?<br \/>\nGenerelt kan man sige at afvikling p\u00e5 SQL (modsat hvad mange tror) IKKE er hurtigere. N\u00e6rmere en smule langsommere&#8230; Til geng\u00e6ld er samtidigheden og databasestabiliteten NOGET h\u00f8jere&#8230; Dvs. en gruppe af brugere vil opleve at de ikke l\u00e5ser (s\u00e5 l\u00e6nge) for hinanden og har man problemer med (typisk i store databaser: dvs. databaser\u00a0over ca. 500MB) at databasefejl, n\u00f8dvendig reindeksering eller at der fjernes TTS&#8217;er konstant &#8211; ja s\u00e5 vil man opleve markante forbedringer&#8230;<\/p>\n<p>En meget v\u00e6rre f\u00e6lde er der dog &#8211; hvis din tilpassede\u00a0kode indeholder konstruktioner i stil med:<\/p>\n<pre>INTRODUCE SalesLine[<strong>RecID<\/strong>, &amp;SLRecID]\r\nIF SalesLine.<strong>RowNumber<\/strong> THEN\r\n\u00a0\u00a0\u00a0\u00a0 ...\r\nENDIF\r\n\r\n<\/pre>\n<p>Umiddelbart skulle man jo tro at ovenst\u00e5ende ville fremfinde en SalesLine-post med RecID==&amp;SLRecID og s\u00e5 kun afvikle det inden i IF-betingelsen hvis der fantes s\u00e5dan en post&#8230; Og s\u00e5dan virker det da ogs\u00e5 p\u00e5 Native.<br \/>\nMEN p\u00e5 SQL er RowNumber ALTID udfyldt i ovenst\u00e5ende&#8230;<br \/>\nBug&#8217;en skyldes nok til dels at RowNumber og RecID altid er samme v\u00e6rdi\u00a0p\u00e5 SQL (nemlig et fortl\u00f8bende nummer p\u00e5 tv\u00e6rs af alle tabeller)\u00a0&#8211; alts\u00e5 p\u00e5 n\u00e6r i dette tilf\u00e6lde, mens det i Native er to forskellige ting (hhv. fortl\u00f8bende nummer indenfor samme tabel (RowNumber)\u00a0og fortl\u00f8bende nummer p\u00e5 tv\u00e6rs af alle tabeller (RecID)). S\u00e5 kernerne ER faktisk forskellige p\u00e5 dette punkt &#8211; og kode der afvikles uden problemer p\u00e5 Native kan vise sig at afvikles forkert p\u00e5 SQL.<br \/>\nAt ovenst\u00e5ende konstruktion fungerer p\u00e5 Native men ikke p\u00e5 SQL er\u00a0farlig &#8211; for det er ulogisk.<\/p>\n<p>Den korrekte konstruktion, der virker b\u00e5de p\u00e5 SQL og Native er i \u00f8vrigt at checke p\u00e5 RecID:<\/p>\n<pre>INTRODUCE SalesLine[<strong>RecID<\/strong>, &amp;SLRecID]\r\nIF SalesLine.<strong>RecID<\/strong> THEN\r\n\u00a0\u00a0\u00a0 ...\r\nENDIF\r\n\r\n<\/pre>\n<p>Vi har naturligvis haft fejlen forbi Microsoft, som dog kendte den i forvejen. Her betragter man dog fejlen som et designvalg og har derfor ikke umiddelbart planer om at rette den (man er formentligt bange for at der er kode i den virkelige verden der s\u00e5 vil g\u00e5 i stykker fordi de udnytter opf\u00f8rslen p\u00e5 SQL).<\/p>\n<p>Lad os slutte af med et\u00a0lille optimeringstip: Har man meget tunge\/langsomme k\u00f8rsler &#8211; eller mulighed for det, s\u00e5 er det i \u00f8vrigt (modsat de fleste logisk SQL-anbefalinger) faktisk en RIGTIG god id\u00e9 at placere SQL-serveren direkte p\u00e5 en terminalserver hvor man s\u00e5 afvikler C5 fra. Vi har set op mod 20% performanceboost (m\u00e5lt med C5s PerformanceTest.XAL), s\u00e5 det kan varmt anbefales hvis du har performance-\/hastighedsproblemer&#8230;<br \/>\nHastighedsfor\u00f8gelsen f\u00e5r man i \u00f8vrigt formentligt ved at det er billigere for C5 at kommunikere direkte med en lokal SQL-server\u00a0fremfor at pakke foresp\u00f8rgslen ned og sende den via netv\u00e6rket til serveren, der s\u00e5 skal pakke den ud, udf\u00f8res den, pakke resultatet ned og sende det tilbage til C5. Egentligt ikke s\u00e5 m\u00e6rkeligt n\u00e5r man t\u00e6nker over det&#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Som regel kan en C5 p\u00e5 Native-databasen umiddelbart skiftes til SQL-databasen, hvis man \u00f8nsker det&#8230; Og det uden problemer af nogen art&#8230; Det kr\u00e6ver naturligvis at is\u00e6r RecID-pegere er angivet korrekt i databasen med referencefelter til enten den korrekte tabels &hellip; <a href=\"https:\/\/scblog.lynge.org\/?p=194\">L\u00e6s resten <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[37,6,4],"tags":[30,15,43,13,22,11,29,23,53,14,21,28,20],"class_list":["post-194","post","type-post","status-publish","format-standard","hentry","category-klassisk-c5","category-klassisk-c5-support","category-klassisk-c5-teknik","tag-bug","tag-business-solutions","tag-c5","tag-damgaard-data","tag-database","tag-dynamics","tag-fejl","tag-hint","tag-klassisk-c5","tag-microsoft","tag-native","tag-sql","tag-udokumenteret"],"_links":{"self":[{"href":"https:\/\/scblog.lynge.org\/index.php?rest_route=\/wp\/v2\/posts\/194","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/scblog.lynge.org\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/scblog.lynge.org\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/scblog.lynge.org\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/scblog.lynge.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=194"}],"version-history":[{"count":9,"href":"https:\/\/scblog.lynge.org\/index.php?rest_route=\/wp\/v2\/posts\/194\/revisions"}],"predecessor-version":[{"id":736,"href":"https:\/\/scblog.lynge.org\/index.php?rest_route=\/wp\/v2\/posts\/194\/revisions\/736"}],"wp:attachment":[{"href":"https:\/\/scblog.lynge.org\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=194"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/scblog.lynge.org\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=194"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/scblog.lynge.org\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=194"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}