{"id":1222,"date":"2022-04-01T15:39:37","date_gmt":"2022-04-01T18:39:37","guid":{"rendered":"https:\/\/gladiston.net.br\/?page_id=1222"},"modified":"2023-05-17T12:01:39","modified_gmt":"2023-05-17T15:01:39","slug":"porque-um-dba-deve-orientar-programadores-a-criarem-querys-parametrizadas","status":"publish","type":"page","link":"https:\/\/gladiston.net.br\/en\/banco-de-dados\/porque-um-dba-deve-orientar-programadores-a-criarem-querys-parametrizadas\/","title":{"rendered":"Why should a DBA guide programmers to create parameterized queries?"},"content":{"rendered":"<p>A problem to be avoided is thinking that parameters within a query are like macro-replacements, a kind of Search\/Replace within queries, as they are not. Parameters are ways to identify values and their types to the DBMS server in an organized and error-free manner and, in addition, the possibility of repeating the same SQL sentence to be more performant. Next, I describe how this is possible.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Using parameterized queries<\/h2>\n\n\n\n<p>Most programmers like to use literal queries, that is, concatenating values to produce a query that you will later read and understand what was requested from the server and compare with what was returned. Here&#039;s an example of a literal query:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:false,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;pascal&quot;,&quot;mime&quot;:&quot;text\/x-pascal&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;Pascal&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;pascal&quot;}\">if Query1.Active then Query1.Close; Query1.SQL.Text:= &#039;UPDATE CLIENTS SET &#039;+ &#039; RAZAO_SOCIAL=&#039;&#039;&#039;+Trim(edtRazaoSocial.Text)+&#039;&#039;&#039;&#039; &#039; WHERE ID_CLIENTE=&#039;+edtID_CLIENTE.Text; Query1.ExecSQL;<\/pre><\/div>\n\n\n\n<p>What&#039;s the problem with the query above? Imagine that the corporate name is <strong>INTELIG S\/A<\/strong> and the CLIENT_ID is 666 then the query with all the concatenation would be as follows:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:false,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;pascal&quot;,&quot;mime&quot;:&quot;text\/x-pascal&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;Pascal&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;pascal&quot;}\">UPDATE CLIENTS SET RAZAO_SOCIAL=&#039;INTELIG S\/A&#039; WHERE ID_CLIENTE=666<\/pre><\/div>\n\n\n\n<p>If you&#039;ve come this far, you probably haven&#039;t seen much of anything. But let&#039;s say now that the corporate name entered was <strong>\u201d\u2013INTELIG S\/A<\/strong>(two single quotes on purpose), what then would the SQL sentence look like? Let&#039;s see:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>UPDATE CLIENTS SET RAZAO_SOCIAL=&#039;&#039;<strong><em>--INTELIG S\/A&#039; WHERE CLIENT_ID=666<\/em><\/strong><\/code><\/pre>\n\n\n\n<p>If you&#039;re good at SQL, you&#039;ve noticed that I&#039;ve turned what&#039;s from the two forward dashes into a comment and now all the customer names will be deleted from the base. So the main problem in writing literal queries is dealing with code injection. Some can use QuotedStr() and this function will solve the issue of quotes, but it is anti-performative especially when we are dealing with long texts, imagine HTML code, RTF or long memos counting the position of the quotes and doubling them. Also, QuotedStr doesn&#039;t resolve issues involving unicode codes, escape characters, and other methods that can sabotage your query. So what&#039;s the solution? Use parameters and signal the end of the query, see the example:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:false,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;pascal&quot;,&quot;mime&quot;:&quot;text\/x-pascal&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;Pascal&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;pascal&quot;}\">if Query1.Active then Query1.Close; Query1.SQL.Clear; Query1.SQL.Add(&#039;UPDATE CLIENTS SET &#039;); Query1.SQL.Add(&#039; RAZAO_SOCIAL=:P_RAZAO_SOCIAL&#039;); Query1.SQL.Add(&#039;WHERE ID_CLIENTE=:P_ID_CLIENTE&#039;); Query1.SQL.Add(&#039;;&#039;); \/\/ signaling the end of the query Query1.ParamByName(&#039;P_RAZAO_SOCIAL&#039;).AsString:=edtRazaoSocial.Text; Query1.ParamByName(&#039;P_ID_CLIENTE&#039;).AsInteger:=StrToInt(edtID_CLIENTE.Text); Query1.ExecSQL;<\/pre><\/div>\n\n\n\n<p>Em nosso exemplo, sob nenhuma hip\u00f3tese nossa query poder\u00e1 ser sabotada pelo tipo de dados que informamos num formul\u00e1rio. Talvez se pergunte porque eu n\u00e3o usei SQL.Text e concatenei tudo, se voc\u00ea viu o artigo anterior a respeito de produtividade na IDE Delphi e Lazarus deve ter notado que fa\u00e7o uso do <a href=\"https:\/\/www.youtube.com\/watch?v=7mKy2h2GD5I\" target=\"_blank\" rel=\"noreferrer noopener\" title=\"MultiPaste\">MultiPaste<\/a> ou Column Mode. Sim, usando estes recursos, escrevo a query dentro do editor SQL(IBExpert, Flamerobin,&#8230;), testo a query, e depois de funcionando ent\u00e3o vou col\u00e1-lo na nossa IDE de programa\u00e7\u00e3o, da\u00ed usando usando <a href=\"https:\/\/www.youtube.com\/watch?v=7mKy2h2GD5I\" target=\"_blank\" rel=\"noreferrer noopener\" title=\"MultiPaste\">MultiPaste<\/a> ou Column Mode gero o c\u00f3digo de forma r\u00e1pida como visto acima, m\u00e3o na roda!<\/p>\n\n\n\n<p>But we&#039;re not done yet, parameterized queries have yet another advantage, if they are very repetitive in our application we can prepare them just once and use them many times, optimizing them for network use.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Using parameterized queries with preparation<\/h2>\n\n\n\n<p>Aprendemos at\u00e9 aqui a orientar programadores a n\u00e3o usarem querys literais, mas usar querys parametrizadas, mas h\u00e1 outro cen\u00e1rio que elas tamb\u00e9m nos beneficiam, vamos imaginar um sistema onde em v\u00e1rias partes  \u00e9 preciso sempre repetir a mesma busca:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:false,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;pascal&quot;,&quot;mime&quot;:&quot;text\/x-pascal&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;Pascal&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;pascal&quot;}\">if Query1.Active then Query1.Close; Query1.SQL.Clear; Query1.SQL.Add(&#039;SELECT status, corporate_id, client_id FROM CLIENTS&#039;); Query1.SQL.Add(&#039;WHERE CNPJ=:P_CNPJ&#039;); Query1.ParamByName(&#039;P_CNPJ&#039;).AsString:=Trim(Search.Text); Query1.Open();<\/pre><\/div>\n\n\n\n<p>Querys como a acima ser\u00e3o executadas no servidor SGBD sempre da mesma forma, (1) fazendo a analise sintatica da query, (2) otimizando a query, (3) calculando custo de opera\u00e7\u00e3o com \u00edndices, (4) compilando para o formato BLR e finalmente (5) executar e se necess\u00e1rio ent\u00e3o retornar o resultado. De todas essas etapas a mais custosa \u00e9 o PLANO(plan) para escolher o \u00edndice adequado porque quanto mais \u00edndices existirem, mais tempo levar\u00e1 a analise, isso contradiz um pouco a ideia de que quanto mais indices existirem \u00e9 melhor, n\u00e3o? Estou me desviando do t\u00f3pico, retomando&#8230;imagine a query acima dentro de um sistema de atendimento com mais de 400 pessoas realizando a mesma consulta, apenas com clientes diferentes (<mark style=\"background-color:#dbdbdb\" class=\"has-inline-color\">WHERE CNPJ=:P_CNPJ<\/mark>), todas ser\u00e3o executadas in\u00fameras vezes e passando pelo mesmo processo a cada consulta. <\/p>\n\n\n\n<p>There is a way to optimize this using parameters, see:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:false,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;pascal&quot;,&quot;mime&quot;:&quot;text\/x-pascal&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;Pascal&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;pascal&quot;}\">if Query1.Active then Query1.Close; Query1.SQL.Clear; Query1.SQL.Add(&#039;SELECT status, social_reason, cnpj FROM CLIENTS&#039;); Query1.SQL.Add(&#039;WHERE ID_CLIENTE=:P_ID_CLIENTE&#039;); if not Query1.Prepared then Query1.Prepare;<\/pre><\/div>\n\n\n\n<p>Notou o Query1.Prepare? O que ele faz? Ele submete ao SGBD a uma &#8220;prepara\u00e7\u00e3o&#8221;, isto \u00e9, nossa query vai for\u00e7ar o SGBD a ir at\u00e9 a \u00faltima etapa, mas n\u00e3o executa, mas manter\u00e1 o BLR e o PLANO e assim nas pr\u00f3ximas execu\u00e7\u00f5es repetitivas n\u00e3o ser\u00e1 necesspario passar por todo o processo novamente. <\/p>\n\n\n\n<p>E se eu n\u00e3o usar o m\u00e9todo <strong>Prepare<\/strong>? Ferramentas de programa\u00e7\u00e3o como o Delphi e Lazarus fazem inferencia, isto \u00e9, acabam preparando do mesmo jeito <strong>s\u00f3 que isso pode acontecer num momento incoveniente do programa e mais de uma vez<\/strong> , ent\u00e3o \u00e9 bom que voc\u00ea fa\u00e7a a prepara\u00e7\u00e3o num momento bem antes a execu\u00e7\u00e3o a querie para que o tempo de prepara\u00e7\u00e3o n\u00e3o se some ao tempo da execu\u00e7\u00e3o.<\/p>\n\n\n\n<p>Como o SGBD saber\u00e1 que uma query preparada j\u00e1 existe? O servidor manter\u00e1 na mem\u00f3ria todas as querys j\u00e1 preparadas em forma de assinatura:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code><strong>SELECT<\/strong> status, social_reason, cnpj <strong>FROM CLIENTS WHERE CLIENT_ID=?<\/strong><\/code><\/pre>\n\n\n\n<p>Esta \u00e9 a assinatura, em alguns SGBDs os nomes dos campos s\u00e3o irrelevantes. Qualquer query similar a assinatura ser\u00e1 reconhecida imediatamente como uma query preparada.<\/p>\n\n\n\n<p>N\u00e3o importa para o SGBD de qual esta\u00e7\u00e3o, programa ou parte do programa venha a query, o que importa \u00e9 a assinatura, se ela for reconhecida ent\u00e3o usar\u00e1 o que j\u00e1 foi preparado. Por isso podemos dizer que querys preparadas n\u00e3o \u00e9 feita para beneficiar apenas 1 conex\u00e3o\/programa, mas muitas conex\u00f5es e muitos programas diferentes onde estatisticamente a mesma consulta acontece. <\/p>\n\n\n\n<p>Notou que eu fa\u00e7o um teste antes de prepar\u00e1-las? Olha s\u00f3:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:false,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;pascal&quot;,&quot;mime&quot;:&quot;text\/x-pascal&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;Pascal&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;pascal&quot;}\">if not Query1.Prepared then Query1.Prepare;<\/pre><\/div>\n\n\n\n<p>Porque fa\u00e7o isso? Parece \u00f3bvio, mas se prepararmos todas as vezes n\u00e3o obteremos a performance que desejamos. A prepara\u00e7\u00e3o deve ser feita uma \u00fanica vez, e nunca mais repetida. Mesmo que eu feche o programa e abrir de novo, a prepara\u00e7\u00e3o deve estar l\u00e1 em alguma parte da mem\u00f3ria do SGBD. <\/p>\n\n\n\n<p>O SGBD ir\u00e1 eliminar da mem\u00f3ria os recursos n\u00e3o utilizados e isso inclui prepara\u00e7\u00f5es &#8220;obsoletas&#8221; ou em &#8220;desuso&#8221;, mas tamb\u00e9m quando explicitamente o programador chama um m\u00e9todo conhecido como &#8220;UnPrepare&#8221; &#8211; falaremos dele mais tarde.<\/p>\n\n\n\n<p>A &#8220;prepara\u00e7\u00e3o&#8221; tamb\u00e9m \u00e9 excelente em transferencias de dados em lote, veja o exemplo:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:false,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;pascal&quot;,&quot;mime&quot;:&quot;text\/x-pascal&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;Pascal&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;pascal&quot;}\">if Query1.Active then\n  Query1.Close;\nQuery1.SQL.Clear;\nQuery1.SQL.Add('SELECT status, razao_social, cnpj FROM CLIENTES');\nQuery1.SQL.Add('WHERE ULTIMO_PEDIDO&amp;lt;dateadd (-5 year to current_date)');\nQuery1.Open()\n\nif Query2.Active then\n  Query2.Close;\nQuery2.SQL.Clear;\nQuery2.SQL.Add('UPDATE CLIENTES SET STATUS=''C'' ');\nQuery2.SQL.Add('WHERE ID_CLIENTE=:P_ID_CLIENTE');\nif not Query2.Prepared then\n  Query2.Prepare;\n\nwhile not Query1.eof do\nbegin\n  (...)\n  if isPrecisaCancelar then\n  begin\n      Query2.ParamByName('P_ID_CLIENTE').AsInteger:=Query1.FieldByName('P_ID_CLIENTE').AsInteger;\n    Query2.ExecSQL;\n  end;  \n  Query1.Next;\nend;\n\nif Query2.Prepared then\n  Query2.UnPrepare;<\/pre><\/div>\n\n\n\n<p>In the example above, the repetition of the same query would be obvious so we performed the \u201cpreparation\u201d and saved time. Another interesting thing that I didn&#039;t mention earlier was that at the end of the process, when I&#039;m not going to use the prepared query anymore, then run:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:false,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;pascal&quot;,&quot;mime&quot;:&quot;text\/x-pascal&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;Pascal&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;pascal&quot;}\">if Query2.Prepared then Query2.UnPrepare;<\/pre><\/div>\n\n\n\n<p>O UnPrepare acima far\u00e1 com que a assinatura de nossa &#8220;prepara\u00e7\u00e3o&#8221; no SGBD seja eliminada, isso \u00e9 \u00fatil porque elimina da mem\u00f3ria do SGBD todos os recursos alocados.<\/p>\n\n\n\n<p>Devo fazer sempre o UnPrepare no final? Quase sempre a resposta \u00e9 &#8220;nunca&#8221;. Geralmente s\u00f3 usamos o &#8220;UnPrepare&#8221; nas situa\u00e7\u00f5es de transferencia de lote de dados, um cen\u00e1rio onde n\u00e3o h\u00e1  outros na rede que poderiam se beneficiar de uma query preparada. Um &#8220;UnPrepare&#8221; quando outros na erde est\u00e3o se beneficiando de queries repetitivas mataria a performance. Ent\u00e3o a regra \u00e9 simples: quando a chance \u00e9 zero de outros repetirem o mesmo procedimento depois que o mesmo j\u00e1 foi executado ent\u00e3o podemos com tranquilidade chamar o m\u00e9todo &#8220;UnPrepare&#8221;, nos outros cen\u00e1rios, voc\u00ea nunca ir\u00e1 us\u00e1-lo.<\/p>\n\n\n\n<p>No v\u00eddeo a seguir, eu demonstro a diferen\u00e7a entre uma query preparada e outra n\u00e3o preparada:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Part 3: Database connection with Zeos, talking about autocommit - Lazarus\" width=\"580\" height=\"326\" src=\"https:\/\/www.youtube.com\/embed\/xHB7oFudD7I?start=271&#038;feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">When not to use the preparation<\/h2>\n\n\n\n<p>Senten\u00e7as SQL s\u00e3o muito flex\u00edveis e cada SGBD tem suas peculiaridades e n\u00e3o \u00e9 poss\u00edvel descrever todas as situa\u00e7\u00f5es, mas quando uma senten\u00e7a \u00e9 ambigua para tomada de decis\u00e3o voc\u00ea deve evitar uma prepara\u00e7\u00e3o. Com exemplo podemos citar o like, quando usamos:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:false,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;pascal&quot;,&quot;mime&quot;:&quot;text\/x-pascal&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;Pascal&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;pascal&quot;}\">SELECT * FROM CLIENTS WHERE RAZAO_SOCIAL LIKE &#039;INDUSTRIA%&#039;<\/pre><\/div>\n\n\n\n<p>In the example above, it is very clear that if there is an index associated with the company name, the DBMS should use it, but what if the query was:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:false,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;pascal&quot;,&quot;mime&quot;:&quot;text\/x-pascal&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;Pascal&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;pascal&quot;}\">SELECT * FROM CLIENTS WHERE RAZAO_SOCIAL LIKE &#039;%INDUSTRIA%&#039;<\/pre><\/div>\n\n\n\n<p>Neste novo exemplo, o SGBD ir\u00e1 ignorar qualquer \u00edndice, pois n\u00e3o faria sentido us\u00e1-los j\u00e1 que todos os registros precisar\u00e3o ser lidos de qualquer forma. Ent\u00e3o imaginaria o que aconteceria se preparasse uma query assim:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:false,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;pascal&quot;,&quot;mime&quot;:&quot;text\/x-pascal&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;Pascal&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;pascal&quot;}\">if Query1.Active then Query1.Close; Query1.SQL.Clear; Query1.SQL.Add(&#039;SELECT * FROM CUSTOMERS&#039;); Query1.SQL.Add(&#039;WHERE RAZAO_SOCIAL LIKE :PESQUISA&#039;); if not Query1.Prepared then Query1.Prepare;<\/pre><\/div>\n\n\n\n<p>Pausa dram\u00e1tica. Como voc\u00ea n\u00e3o consegue determinar o que a pessoa digitar\u00e1 na barra de pesquisa, vamos inventar que a pessoa tenha pesquisado por:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>'INDUSTRIA%'<\/code><\/pre>\n\n\n\n<p>Como ela \u00e9 a primeira pessoa a fazer a prepara\u00e7\u00e3o, nosso PLANO seria usar um \u00edndice por Raz\u00e3o Social, certo? Sim, isto estaria certo, mas note que a mesma j\u00e1 foi preparada e h\u00e1 no SGBD a assinatura que j\u00e1 indicar\u00e1 o PLANO a ser executado. Da\u00ed vem a segunda pessoa e no campo de pesquisa faz a seguinte busca: <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>'%INDUSTRIA%'  <\/code><\/pre>\n\n\n\n<p>Como a query j\u00e1 foi preparada, as pesquisas seguintes usar\u00e3o o mesmo PLANO, ou seja, voc\u00ea for\u00e7ou o uso de um \u00edndice imprest\u00e1vel ao LIKE que s\u00f3 o far\u00e1 perder tempo. <\/p>\n\n\n\n<p>Alguns SGBD podem detectar a situa\u00e7\u00e3o acima atrav\u00e9s de probabilidades e estat\u00edsticas e agir de forma preditiva, mas \u00e9 muito melhor quando programadores evitam situa\u00e7\u00f5es assim. Hoje um programador pode usar um banco e amanh\u00e3 outro completamente diferente que n\u00e3o seja t\u00e3o preditivo e espere que o desenvolvedor seja mais esperto e n\u00e3o submeta armadilhas ao pr\u00f3prio SGBD. <\/p>\n\n\n\n<p>Respondendo logo a quest\u00e3o, em situa\u00e7\u00f5es amb\u00edguas evite usar par\u00e2metro e prefira o QuotedStr() em seu lugar:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:false,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;pascal&quot;,&quot;mime&quot;:&quot;text\/x-pascal&quot;,&quot;theme&quot;:&quot;default&quot;,&quot;lineNumbers&quot;:true,&quot;styleActiveLine&quot;:true,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;TrpContentRestriction&quot;:{&quot;restriction_type&quot;:&quot;exclude&quot;,&quot;selected_languages&quot;:[],&quot;panel_open&quot;:true},&quot;language&quot;:&quot;Pascal&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;pascal&quot;}\">if Query1.Active then Query1.Close; Query1.SQL.Clear; Query1.SQL.Add(&#039;SELECT * FROM CUSTOMERS&#039;); Query1.SQL.Add(&#039;WHERE RAZAO_SOCIAL LIKE &#039;+QuotedStr(edtPesquisa.Text));<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Both the parameters and the preparation of a query do not depend on the programming language, as this feature is in all of them. These features serve a well-defined purpose: to improve and streamline research. If you notice that programmers on your team aren&#039;t using them, send the link to this article.<\/p>\n\n\n\n<p>Each DBMS is different, some of them subvert poorly made queries, others use algorithms to improve a poorly performing query, but make no mistake, if programmers are efficient in the origin of the query, the database will be much more performant, otherwise, the database will be a obese turtle with 3 legs.<\/p>","protected":false},"excerpt":{"rendered":"<p>Um problema a ser evitado \u00e9 achar que par\u00e2metros dentro de uma query s\u00e3o como macro-substitui\u00e7\u00f5es, uma especie de Search\/Replace dentro de querys, pois n\u00e3o s\u00e3o. Par\u00e2metros s\u00e3o formas de identificar para o servidor SGBD os valores e seus tipos de forma organizada e n\u00e3o sujeita a erros e al\u00e9m disso, a possibilidade de repeti\u00e7\u00e3o [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":0,"parent":1109,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"templates\/template-full-width.php","meta":{"footnotes":""},"class_list":["post-1222","page","type-page","status-publish","hentry"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/gladiston.net.br\/en\/wp-json\/wp\/v2\/pages\/1222","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gladiston.net.br\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/gladiston.net.br\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/gladiston.net.br\/en\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/gladiston.net.br\/en\/wp-json\/wp\/v2\/comments?post=1222"}],"version-history":[{"count":54,"href":"https:\/\/gladiston.net.br\/en\/wp-json\/wp\/v2\/pages\/1222\/revisions"}],"predecessor-version":[{"id":2246,"href":"https:\/\/gladiston.net.br\/en\/wp-json\/wp\/v2\/pages\/1222\/revisions\/2246"}],"up":[{"embeddable":true,"href":"https:\/\/gladiston.net.br\/en\/wp-json\/wp\/v2\/pages\/1109"}],"wp:attachment":[{"href":"https:\/\/gladiston.net.br\/en\/wp-json\/wp\/v2\/media?parent=1222"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}