Quais são os anti-padrões SQL mais comuns? [fechadas]

232

Todos nós que trabalhamos com bancos de dados relacionais aprendemos (ou estamos aprendendo) que o SQL é diferente. Obter os resultados desejados e fazê-lo com eficiência envolve um processo tedioso, parcialmente caracterizado por aprender paradigmas desconhecidos e descobrir que alguns de nossos padrões de programação mais familiares não funcionam aqui. Quais são os antipadrões comuns que você já viu (ou se comprometeu)?

maior
fonte
Essa é uma pergunta que não está em conformidade com os padrões mais recentes sobre que tipo de pergunta é apropriado para o estouro de pilha. Quando solicitado, isso pode não ter sido verdade.
David Manheim
@casperOne não existe uma cláusula de "significado histórico" que permita que essa questão seja aceita?
187 Amy B
26
Acho triste que uma das perguntas mais úteis no site wohole seja fechada por não ser construtiva.
HLGEM
11
@HLGEM Eu concordo totalmente. Esta questão é um exemplo perfeito de tudo o que está errado com Stackexchange
Kevin Morse
1
O tópico é absolutamente importante e relevante. Mas a pergunta é muito aberta, e é por isso que as respostas estão descrevendo cada um dos insetos antipadrão pessoal de um engenheiro.
Shane

Respostas:

156

Estou constantemente decepcionado com a tendência da maioria dos programadores de misturar sua lógica de interface do usuário na camada de acesso a dados:

SELECT
    FirstName + ' ' + LastName as "Full Name",
    case UserRole
        when 2 then "Admin"
        when 1 then "Moderator"
        else "User"
    end as "User's Role",
    case SignedIn
        when 0 then "Logged in"
        else "Logged out"
    end as "User signed in?",
    Convert(varchar(100), LastSignOn, 101) as "Last Sign On",
    DateDiff('d', LastSignOn, getDate()) as "Days since last sign on",
    AddrLine1 + ' ' + AddrLine2 + ' ' + AddrLine3 + ' ' +
        City + ', ' + State + ' ' + Zip as "Address",
    'XXX-XX-' + Substring(
        Convert(varchar(9), SSN), 6, 4) as "Social Security #"
FROM Users

Normalmente, os programadores fazem isso porque pretendem vincular seus conjuntos de dados diretamente a uma grade, e é conveniente ter o formato SQL Server do lado do servidor do que o formato no cliente.

Consultas como a mostrada acima são extremamente frágeis porque acoplam firmemente a camada de dados à camada da interface do usuário. Além disso, esse estilo de programação impede completamente que os procedimentos armazenados sejam reutilizáveis.

Julieta
fonte
10
Um bom padrão poster-filho para o acoplamento máximo no maior número possível de camadas / camadas de abstração.
dkretz
3
Pode não ser bom para o desacoplamento, embora, por razões de desempenho, eu tenha feito coisas assim com frequência, as alterações iterativas feitas pelo SQL Server são mais rápidas do que as feitas pelo código na camada intermediária. Não entendo seu ponto de reutilização - nada impede você de executar o SP e renomear as colunas se assim o desejar.
Joe Pineda
54
O meu favorito é quando as pessoas incorporar HTML e JavaScript, por exemplo SELECT '<a href=... onclick="">' + nome '</a>'
Matt Rogish
15
Com consultas como essa, você pode editar a grade em um site com uma simples declaração de alteração. Ou altere o conteúdo de uma exportação ou reformate uma data em um relatório. Isso faz os clientes felizes e economiza tempo. Então, obrigada, mas não, obrigada. Farei perguntas como esta.
Andomar
4
@ Matt Rogish - jesus, alguém realmente faz isso?
Axarydax
118

Aqui estão os meus 3 principais.

Número 1. Falha ao especificar uma lista de campos. (Editar: para evitar confusão: esta é uma regra de código de produção. Ela não se aplica a scripts de análise únicos - a menos que eu seja o autor.)

SELECT *
Insert Into blah SELECT *

deveria estar

SELECT fieldlist
Insert Into blah (fieldlist) SELECT fieldlist

Número 2. Usando um cursor e um loop while, quando um loop while com uma variável loop for suficiente.

DECLARE @LoopVar int

SET @LoopVar = (SELECT MIN(TheKey) FROM TheTable)
WHILE @LoopVar is not null
BEGIN
  -- Do Stuff with current value of @LoopVar
  ...
  --Ok, done, now get the next value
  SET @LoopVar = (SELECT MIN(TheKey) FROM TheTable
    WHERE @LoopVar < TheKey)
END

Número 3. DateLogic através dos tipos de string.

--Trim the time
Convert(Convert(theDate, varchar(10), 121), datetime)

Deveria estar

--Trim the time
DateAdd(dd, DateDiff(dd, 0, theDate), 0)

Vi um pico recente de "Uma consulta é melhor que duas, certo?"

SELECT *
FROM blah
WHERE (blah.Name = @name OR @name is null)
  AND (blah.Purpose = @Purpose OR @Purpose is null)

Essa consulta requer dois ou três planos de execução diferentes, dependendo dos valores dos parâmetros. Apenas um plano de execução é gerado e preso no cache para este texto sql. Esse plano será usado independentemente do valor dos parâmetros. Isso resulta em baixo desempenho intermitente. É muito melhor escrever duas consultas (uma consulta por plano de execução pretendido).

David B
fonte
7
hmmm, eu darei um +1 para os pontos 2 e 3 sozinhos, mas os desenvolvedores exageram na regra 1. Ele tem seu lugar às vezes.
annakata 6/12/08
1
Qual é o raciocínio por trás do nº 1?
jalf
29
Quando você usa select *, obtém o que estiver na tabela. Essas colunas podem alterar nomes e ordem. O código do cliente depende frequentemente de nomes e ordem. A cada 6 meses, perguntam-me como preservar a ordem das colunas ao modificar uma tabela. Se a regra fosse seguida, não importaria.
Amy B
Eu usei o número 2 algumas vezes, outros eu segui a rota do cursor (embora primeiro salve os resultados da consulta em uma tabela var, abra o cursor nela). Eu sempre me perguntei se alguém fez um teste de desempenho de ambos.
Joe Pineda
4
... mas é claro que os cursores devem quase sempre ser o último recurso, após falha em descobrir como fazer o trabalho com SQL baseado em conjunto. Certa vez, passei cerca de 45 minutos dissecando cuidadosamente um cursor PL / SQL gigantesco e horrendo em um procedimento armazenado (desenhou diagramas da coisa podre), que preenchia uma grande tabela temporária e selecionava o conteúdo da tabela temporária de volta ao chamador para renderizar um relatório. Demorou 8,5 minutos para executar, em hardware substancial. Depois de desenhar a coisa toda, consegui substituí-la por uma única consulta que retornou os mesmos resultados em menos de 2 segundos. Cursores, homem ...
Craig
71
  • Campos de senha legíveis por humanos , por exemplo. Auto-explicativo.

  • Usando LIKE contra colunas indexadas , estou quase tentado a dizer LIKE em geral.

  • Reciclando valores de PK gerados por SQL.

  • Surpresa, ninguém mencionou a mesa divina ainda. Nada diz "orgânico" como 100 colunas de sinalizadores de bits, grandes seqüências de caracteres e números inteiros.

  • Depois, há o padrão "Sinto falta de arquivos .ini" : armazenando CSVs, seqüências delimitadas por pipe ou outros dados necessários para análise em grandes campos de texto.

  • E para servidor MS SQL o uso de cursores em tudo . Existe uma maneira melhor de executar qualquer tarefa do cursor.

Editado porque há tantos!

annakata
fonte
19
errado sobre cursores, eu hesitaria em dizer fazer qualquer coisa em particular é 100% certo ou 100% errado
Shawn
4
Até agora, todos os exemplos de defesa de cursor que vi estão usando a ferramenta errada para o trabalho. Mas se tudo que você conhece é SQL, você o usa de forma inadequada ou aprende a escrever outros tipos de software.
dkretz 08/12/08
3
@tuinstoel: Como o LIKE '% blah%' consegue usar um índice? A indexação depende da ordem e este exemplo pesquisa uma posição intermediária aleatória de uma sequência. (Índices de encomendar pelo 1º 1º caráter, e assim olhar para o meio 4 caracteres dá uma ordem praticamente aleatório ...)
MatBailie
12
Na maioria dos servidores de banco de dados (pelo menos os que eu usei), o LIKE pode usar índices ... desde que seja uma pesquisa de prefixo (LIKE 'xxx%') - ou seja, desde que os caracteres curinga não vem em primeiro lugar na cadeia de pesquisa. Eu acho que você pode estar falando com propósitos diferentes aqui um pouco.
Cowan
10
É como você não gosta LIKE '%LIKE'.
Johan
62

Não precisa se aprofundar: não usar instruções preparadas.

stesch
fonte
3
Sim. Segui de perto no mesmo contexto, na minha experiência, com "não capturar erros".
22468 dkretz
1
@stesch: isso não é nada comparado a usar visualizações e ter uma data de relatório variável. As visualizações são um antipadrão se você tiver uma data de relatório variável (presumo que a maioria dos aplicativos tenha). Adicione isso em uma resposta separada, mas está fechado, infelizmente.
Stefan Steiger
56

Usando aliases de tabela sem sentido:

from employee t1,
department t2,
job t3,
...

Torna a leitura de uma instrução SQL grande muito mais difícil do que precisa

Tony Andrews
fonte
49
apelido? inferno que eu já vi nomes de coluna reais como essa
annakata
10
aliases concisos estão OK. Se você quiser um nome significativo, não use um apelido.
Joel Coehoorn
43
Ele não disse "conciso", ele disse "sem sentido". No meu livro, não haveria nada de errado em usar e, dej como alias na consulta de exemplo.
Robert Rossney 7/12/08
11
Absolutamente, Robert - e, d, ej ficariam bem comigo.
18713 Tony TonysDec
8
Eu usaria emp para empregado, dep para departamento e emprego para emprego (ou talvez jb) :) #
485 Andrei Rînea
53
var query = "select COUNT(*) from Users where UserName = '" 
            + tbUser.Text 
            + "' and Password = '" 
            + tbPassword.Text +"'";
  1. Confiando cegamente na entrada do usuário
  2. Não usando consultas parametrizadas
  3. Senhas de texto não criptografado
Will
fonte
Tudo isso pode ser útil, usando um resumo de banco de dados em uma camada de algum (qualquer) tipo.
7608 dkretz
@doofledorfer: Concordo, uma camada intermediária seria definitivamente melhor em um caso como esse, além de fornecer o cache de resultados como um bom efeito colateral.
Joe Pineda
Exemplo impressionante. Se um desenvolvedor pensa em como substituí-lo por uma boa solução, ele está no meio do caminho para se tornar um desenvolvedor SQL decente.
Steve McLeod
46

Meus insetos são as tabelas de acesso de 450 colunas que foram reunidas pelo filho de 8 anos da melhor amiga do diretor de administração e a tabela de pesquisa que só existe porque alguém não sabe como normalizar uma estrutura de dados corretamente.

Normalmente, esta tabela de pesquisa se parece com isso:

EU NÃO FIZ,
Nome NVARCHAR (132),
IntValue1 INT,
IntValue2 INT,
CharValue1 NVARCHAR (255),
CharValue2 NVARCHAR (255),
Date1 DATETIME,
Date2 DATETIME

Perdi a conta do número de clientes que vi que têm sistemas que dependem de abominações como essa.

Pete OHanlon
fonte
1
Pior ainda, eu li essa versão no mais novo do Access que está realmente suportado automaticamente, o que eu temo vai incentivar mais deste valor1, valor2, Value3 ... fetichismo coluna
Joe Pineda
Espere - então o filho de 8 anos é o filho do groomer de cães?
Barrypicker #
28

Os que eu mais não gosto são

  1. Usando espaços ao criar tabelas, sprocs etc. Estou bem com CamelCase ou under_scores e singular ou plural e MAIÚSCULAS ou minúsculas, mas preciso me referir a uma tabela ou coluna [com espaços], especialmente se [estiver estranhamente espaçada] (sim, Eu me deparei com isso) realmente me irrita.

  2. Dados não normalizados. Uma tabela não precisa ser perfeitamente normalizada, mas quando encontro uma tabela de funcionários que possui informações sobre sua pontuação de avaliação atual ou sobre qualquer outra coisa principal, isso me diz que provavelmente precisarei criar uma tabela separada em algum momento e tente mantê-los sincronizados. Normalizarei os dados primeiro e, em seguida, se vir um local em que a desnormalização ajuda, considerarei.

  3. Uso excessivo de visualizações ou cursores. As visualizações têm um objetivo, mas quando cada tabela é agrupada em uma visualização, é demais. Eu tive que usar cursores algumas vezes, mas geralmente você pode usar outros mecanismos para isso.

  4. Acesso. Um programa pode ser um antipadrão? Temos o SQL Server no meu trabalho, mas várias pessoas usam o acesso devido à sua disponibilidade, "facilidade de uso" e "simpatia" a usuários não técnicos. Há muito aqui para entrar, mas se você já esteve em um ambiente semelhante, você sabe.

Jamal Hansen
fonte
2
# 4 - existe outro thread apenas para <a href=' stackoverflow.com/questions/327199/…> :).
22468 dkretz
4
O acesso NÃO é um DBMS. É um ambiente RAD, com um gerenciador de banco de dados muito simples incluído. SQL Server, Oracle, et al. vai não substituí-lo, a menos que você adicionar um VB-como linguagem e um Crystal Reports como facilidade.
Joe Pineda
26

use SP como o prefixo do nome do procedimento de armazenamento, porque ele primeiro procurará no local dos procedimentos do sistema, em vez dos personalizados.

Oscar Cabrero
fonte
1
Também pode ser estendido para o uso de qualquer outro prefixo comum para todos os procedimentos armazenados, dificultando a seleção de uma lista classificada.
22468 dkretz
7
+1 para o comentário doofledorfer !! Eu já vi isso muito, acho esse idiota e, de fato, torna muito difícil a busca por um determinado SP !!! Também estendido para "vw_" para visualizações, "tbl_" para tabelas e afins, como eu os odeio!
Joe Pineda
1
Os prefixos pode ser útil se você está scripting os objetos para arquivos (por exemplo: para controle de origem, as implantações ou migração)
Rick
1
Por que diabos seria útil prefixar cada procedimento armazenado com sp ou usp? Isso dificulta a varredura da lista para a que você deseja.
Ryan Lundy
25

Uso excessivo de tabelas e cursores temporários.

Rockcoder
fonte
2
Boa evidência de que "tudo o que sei são linguagens processuais".
dkretz
2
O uso excessivo de qualquer coisa é, por definição, indesejável. Um exemplo específico de onde o uso de tabelas temporárias / cursores não seria necessário seria útil.
Jace Rea
6
Vejo principalmente tabelas temporárias subutilizadas. com o SQL Server, geralmente você obtém ganhos de desempenho executando várias tabelas temporárias em vez de uma consulta monolítica.
Cervo
24

Para armazenar valores de tempo, apenas o fuso horário UTC deve ser usado. A hora local não deve ser usada.

Frank Schwieterman
fonte
3
Ainda não encontrei uma solução simples e boa para converter do UTC para o horário local em datas no passado, quando o horário de verão deveria ser considerado, com datas de alteração variadas em anos e países, além de todas as exceções dentro dos países. Portanto, o UTC não o salva da complexidade da conversão. No entanto, é importante ter uma maneira de conhecer o fuso horário de cada data e hora armazenada.
ckarras
1
@CsongorHalmai Muitos lugares praticam o horário de verão, portanto, os valores de tempo dentro de uma hora após o horário podem ser ambíguos.
Frank Schwieterman
Certamente, isso é certo para o presente e o passado, mas para o futuro, especialmente para o futuro bastante distante, fusos horários explícitos costumam ser uma necessidade. Se você tem uma opção de 30 anos que acabou de ser escrita e expira em 2049-09-27T17: 00: 00 no horário de Nova York, não pode assumir cegamente que serão 21: 00: 00Z. O Congresso dos EUA pode muito bem mudar as regras do horário de verão. Você deve manter a hora local e o fuso horário verdadeiro (América / Nova_Iorque) separados.
John Cowan
23

usando @@ IDENTITY em vez de SCOPE_IDENTITY ()

Citado nesta resposta :

  • @@ IDENTITY retorna o último valor de identidade gerado para qualquer tabela na sessão atual, em todos os escopos. Você precisa ter cuidado aqui, já que é através de escopos. Você pode obter um valor de um gatilho, em vez de sua declaração atual.
  • SCOPE_IDENTITY retorna o último valor de identidade gerado para qualquer tabela na sessão atual e o escopo atual. Geralmente o que você deseja usar.
  • IDENT_CURRENT retorna o último valor de identidade gerado para uma tabela específica em qualquer sessão e qualquer escopo. Isso permite especificar de qual tabela você deseja obter o valor, caso as duas acima não sejam exatamente o que você precisa (muito raro). Você pode usar isso se desejar obter o valor atual de IDENTITY para uma tabela na qual você não inseriu um registro.
Brann
fonte
+1 muito verdadeiro, poderia causar erros que seriam difíceis de eliminar
Axarydax 16/01
23

Reutilizar um campo "morto" para algo a que não se destinava (por exemplo, armazenar dados do usuário em um campo "Fax") - muito tentador como uma solução rápida!

FruitBreak
fonte
21
select some_column, ...
from some_table
group by some_column

e assumindo que o resultado será classificado por alguma_coluna. Eu já vi isso um pouco com a Sybase, onde a suposição se mantém (por enquanto).

Adrian Pronk
fonte
1
upvote para sempre assumindo ordem de classificação, só porque era assim que ele mostrou-se na ferramenta de consulta que uma vez
Joel Coehoorn
3
Eu já vi isso relatado como um bug mais de uma vez.
7608 dkretz
6
no MySQL, está documentado para ordenar. < dev.mysql.com/doc/refman/5.0/en/select.html >. Então culpe o MySQL (novamente).
Derobert
1
No Oracle, os resultados não classificados (quase) sempre correspondiam ao agrupamento - até a versão 10G. Muito trabalho para os desenvolvedores que costumavam deixar de fora o ORDER BY!
22313 Tony Tonys
1
Eu estava mesmo em uma aula de treinamento em que isso foi declarado um fato para o SQL Server. Eu tive que protestar muito alto. Para salvar apenas para digitar 20 caracteres, você depende de um comportamento obscuro ou não documentado.
21411 erikkallen
20
SELECT FirstName + ' ' + LastName as "Full Name", case UserRole when 2 then "Admin" when 1 then "Moderator" else "User" end as "User's Role", case SignedIn when 0 then "Logged in" else "Logged out" end as "User signed in?", Convert(varchar(100), LastSignOn, 101) as "Last Sign On", DateDiff('d', LastSignOn, getDate()) as "Days since last sign on", AddrLine1 + ' ' + AddrLine2 + ' ' + AddrLine3 + ' ' + City + ', ' + State + ' ' + Zip as "Address", 'XXX-XX-' + Substring(Convert(varchar(9), SSN), 6, 4) as "Social Security #" FROM Users

Ou, amontoando tudo em uma linha.

Radu
fonte
Usei a consulta de um comentário anterior, apenas porque essa foi a primeira instrução SQL que eu tinha disponível.
Jasper Bekkers 19/04/2009
17
  • A FROM TableA, TableB WHEREsintaxe para JOINS em vez deFROM TableA INNER JOIN TableB ON

  • Fazendo suposições de que uma consulta será retornada classificada de uma certa maneira sem inserir uma cláusula ORDER BY, apenas porque foi dessa maneira que ela apareceu durante o teste na ferramenta de consulta.

Joel Coehoorn
fonte
5
Meus DBAs Oracle sempre reclamam que eu uso "junções ANSI", ou seja, o que você apresenta da maneira correta. Mas continuo fazendo isso e suspeito que no fundo eles sabem que é melhor.
Steve McLeod
1
Suspeito que a Oracle deseje que o SQL padrão desapareça. :-) Além disso, você não pode misturar JOINS implícitos e explícitos (também conhecido como ANSI JOINs) no MySQL 5 - ele não funciona. Esse é outro argumento para JIONs explícitas.
staticsan
3
Eu diria que mesmo A INNER JOIN B ON é um anti-padrão. Eu prefiro A INNER JOIN B USING.
John Nilsson
O Oracle suporta a sintaxe ANSI agora, mas eles costumavam ter essa sintaxe realmente estranha para junções externas no passado e ainda há muitas pessoas usando-a.
Cervo
bem ... a Oracle ainda não permitirá que você use junções ANSI para exibições materializadas rapidamente atualizáveis ​​e em confirmação
Gerrat 17/18
14

Aprendendo SQL nos primeiros seis meses de sua carreira e nunca aprendendo mais nada nos próximos 10 anos. Em particular, não aprendendo ou usando efetivamente os recursos SQL de janela / analítica. Em particular, o uso de over () e partição por.

As funções da janela, como funções agregadas, executam uma agregação em um conjunto definido (um grupo) de linhas, mas, em vez de retornar um valor por grupo, as funções da janela podem retornar vários valores para cada grupo.

Consulte o Apêndice A do O'Reilly SQL Cookbook para obter uma boa visão geral das funções de janelas.

Brian
fonte
12

Preciso colocar meu favorito atual aqui, apenas para completar a lista. Meu antipadrão favorito não está testando suas consultas .

Isso se aplica quando:

  1. Sua consulta envolve mais de uma tabela.
  2. Você acha que possui um design ideal para uma consulta, mas não se preocupe em testar suas suposições.
  3. Você aceita a primeira consulta que funciona, sem nenhuma pista sobre se ela está quase otimizada.

E todos os testes executados com dados atípicos ou insuficientes não contam. Se for um procedimento armazenado, coloque a instrução de teste em um comentário e salve-a com os resultados. Caso contrário, coloque-o em um comentário no código com os resultados.

le dorfier
fonte
Uma técnica muito útil para o teste T-SQL mínimo: no arquivo .SQL onde você define seu SP, UDF etc. imediatamente após criar um teste de bloco como IF 1 = 2 BEGIN (casos de exemplo para o seu código, com resultados esperados como comentários) END
Joe Pineda
O SQL Server analisa o código dentro do bloco de teste, mesmo que nunca seja executado. Portanto, quando seu objeto for modificado e receber mais parâmetros, ou de tipo diferente, etc., ou se um objeto for modificado, você receberá um erro apenas solicitando um plano de execução!
Joe Pineda
Nem sempre é possível testar com dados reais. Geralmente, o servidor de desenvolvimento / servidor de "teste" é mal pago e recebe uma fração do servidor ativo. Geralmente, os testes são desaprovados contra o servidor ativo. Alguns lugares são melhores e possuem um servidor de teste ou armazenamento temporário com dados ativos.
Cervo
11

Abuso temporário da tabela.

Especificamente esse tipo de coisa:

SELECT personid, firstname, lastname, age
INTO #tmpPeople
FROM People
WHERE lastname like 's%'

DELETE FROM #tmpPeople
WHERE firstname = 'John'

DELETE FROM #tmpPeople
WHERE firstname = 'Jon'

DELETE FROM #tmpPeople
WHERE age > 35

UPDATE People
SET firstname = 'Fred'
WHERE personid IN (SELECT personid from #tmpPeople)

Não crie uma tabela temporária a partir de uma consulta, apenas para excluir as linhas que você não precisa.

E sim, vi páginas de código neste formulário nos bancos de dados de produção.

geofftnz
fonte
1
+1, eu concordo. Embora eu tenha encontrado pelo menos um ou dois casos em que essa técnica melhorou o desempenho - as consultas envolvidas eram complexas para dizer o mínimo.
a'r
1
Verdade - eles têm um lugar, não apenas em cada consulta :)
geofftnz
1
Às vezes você deve fazer isso se as condições forem super complicadas. É verdade que pode ser abusado ao extremo. Mas muitas vezes uma exclusão simples é muito mais simples que a lógica para obter o caso na consulta inicial. Às vezes, também, se a cláusula não for sargível, a consulta inicial diminuirá. Mas apenas fazê-lo na tabela temporária menor é mais eficiente. Outras vezes, você continua adicionando casos que os empresários continuam adicionando após o fato.
Cervo
9

Visão contrária: excesso de obsessão com normalização.

A maioria dos sistemas SQL / RBDBs oferece muitos recursos (transações, replicação) que são bastante úteis, mesmo com dados não normalizados. O espaço em disco é barato e, às vezes, pode ser mais simples (código mais fácil, tempo de desenvolvimento mais rápido) manipular / filtrar / pesquisar dados buscados, do que escrever o esquema 1NF e lidar com todos os aborrecimentos nele (junções complexas, subselects desagradáveis) etc).

Descobri que os sistemas super normalizados costumam ser otimização prematura, especialmente durante os estágios iniciais de desenvolvimento.

(mais pensamentos sobre isso ... http://writeonly.wordpress.com/2008/12/05/simple-object-db-using-json-and-python-sqlite/ )

Gregg Lind
fonte
22
Eu acho que a não normalização costuma ser otimização prematura.
Tuinstoel
Às vezes é, às vezes não é. Felizmente, muitas vezes é fácil testar, e diferentes opções funcionam com diferentes necessidades de banco de dados.
Gregg Lind
17
A normalização não é apenas para economia de espaço em disco. É também para criar uma fonte autorizada para os dados. Se os dados são armazenados em apenas um local, a consistência não é um subproduto da codificação cuidadosa, mas um subproduto do design.
Grant Johnson
Armazenar dados compostos no formato JSON é uma coisa: há cada vez mais suporte para eles e é uma troca consciente. O uso de valores separados por vírgula (ou o que seja) na tentativa de salvar uma junção é tostão e insensato.
John Cowan
As soluções noSQL estão mostrando um benefício de desempenho ao custo de dados duplicados, eliminando as pesquisas de várias tabelas. Coloca a coisa toda normalização em sua cabeça. Em alguns exemplos, os dados são coletados em vários locais para garantir que um processo tenha o tempo de resposta mais rápido possível. Obviamente, perguntas sobre fontes oficiais entram em cena.
Barrypicker #
9

Acabei de montar este, com base em algumas das respostas SQL aqui no SO.

É um antipadrão sério pensar que os gatilhos são para bancos de dados, assim como os manipuladores de eventos são para OOP. Existe essa percepção de que qualquer lógica antiga pode ser acionada para ser acionada quando uma transação (evento) acontece em uma tabela.

Não é verdade. Uma das grandes diferenças é que os gatilhos são síncronos - com uma vingança, porque são síncronos em uma operação definida, não em uma operação de linha. No lado OOP, exatamente o oposto - os eventos são uma maneira eficiente de implementar transações assíncronas.

dkretz
fonte
8

Procedimentos ou funções armazenados sem nenhum comentário ...

Bliek
fonte
And views;) Funções true, exceto funções com valor de tabela (= visualizações com parâmetros).
Stefan Steiger
7

1) Não sei se é um antipadrão "oficial", mas não gosto e tento evitar literais de string como valores mágicos em uma coluna do banco de dados.

Um exemplo da tabela 'image' da MediaWiki:

img_media_type ENUM("UNKNOWN", "BITMAP", "DRAWING", "AUDIO", "VIDEO", 
    "MULTIMEDIA", "OFFICE", "TEXT", "EXECUTABLE", "ARCHIVE") default NULL,
img_major_mime ENUM("unknown", "application", "audio", "image", "text", 
    "video", "message", "model", "multipart") NOT NULL default "unknown",

(Eu só noto caixa diferente, outra coisa a evitar)

Eu projeto casos como pesquisas int em tabelas ImageMediaType e ImageMajorMime com chaves primárias int.

2) conversão de data / string que depende de configurações específicas do NLS

CONVERT(NVARCHAR, GETDATE())

sem identificador de formato

devio
fonte
E também não há indentação sintática. Argghh.
dkretz
2
Por que isso é ruim? certamente, se você está tentando expressar um conjunto de valores, isso funciona tão bem quanto uma tabela de pesquisa e se ajusta melhor ao código que a chama. Eu preferiria ter uma enumeração no código do meu aplicativo que mapeia uma restrição de enumeração no meu banco de dados do que uma enumeração no código do meu aplicativo que mapeia linhas específicas de uma tabela de pesquisa. Parece mais limpo.
Jack Ryan
@JackRyan: Isso é ruim, porque quando você altera a lista de enum mais tarde, precisa se lembrar de alterá-la em dois lugares agora. Isso viola a SECA . O banco de dados deve ser a única fonte de verdade.
Gerrat 17/05/19
7

Subconsultas idênticas em uma consulta.

EvilTeach
fonte
10
Infelizmente, às vezes você simplesmente não pode evitar que - no SQL 2000 não havia "COM" palavra-chave, e usando UDFs para encapsular subconsultas comuns em algum momento leva a penalidades de desempenho, MS culpa sobre isso ...
Joe Pineda
Bem, espero que eles possam adicionar um dia desses.
21468 EvilTeach
No SQL 2000, você pode usar variáveis ​​de tabela.
recursivo
@ recursive: você não pode ter índices em uma variável da tabela, o que geralmente a torna mais lenta que uma subconsulta. No entanto, você pode usar uma tabela temporária com índices personalizados.
Rick
Legal, trabalha com SQL há anos e nem sabia que existem expressões comuns de tabela (embora eu as precisasse). Agora eu faço! Obrigado!
Sleske 29/10/2009
7
  • A visão alterada - uma visão alterada com muita frequência e sem aviso ou motivo. A mudança será notada no momento mais inapropriado ou, pior, errada e nunca notada. Talvez seu aplicativo seja interrompido porque alguém pensou em um nome melhor para essa coluna. Como regra, as exibições devem estender a utilidade das tabelas base, mantendo um contrato com os consumidores. Corrija os problemas, mas não adicione recursos ou pior comportamento de alteração, pois isso cria uma nova exibição. Para mitigar, não compartilhe visualizações com outros projetos e use CTEs quando as plataformas permitirem. Se sua loja possui um DBA, você provavelmente não poderá alterar as visualizações, mas todas as suas visualizações estarão desatualizadas e / ou inúteis nesse caso.

  • O! Paramed - uma consulta pode ter mais de uma finalidade? Provavelmente, mas a próxima pessoa que a ler não saberá até profunda meditação. Mesmo que você não precise deles agora, é provável que sim, mesmo que seja "apenas" para depurar. A adição de parâmetros reduz o tempo de manutenção e mantém as coisas SECA. Se você tiver uma cláusula where, deverá ter parâmetros.

  • O caso sem CASE -

    SELECT  
    CASE @problem  
      WHEN 'Need to replace column A with this medium to large collection of strings hanging out in my code.'  
        THEN 'Create a table for lookup and add to your from clause.'  
      WHEN 'Scrubbing values in the result set based on some business rules.'  
        THEN 'Fix the data in the database'  
      WHEN 'Formating dates or numbers.'   
        THEN 'Apply formating in the presentation layer.'  
      WHEN 'Createing a cross tab'  
        THEN 'Good, but in reporting you should probably be using cross tab, matrix or pivot templates'   
    ELSE 'You probably found another case for no CASE but now I have to edit my code instead of enriching the data...' END  
jason saldo
fonte
Adorei esse terceiro. Eu já estou usando-lo localmente ...
alphadogg
Obrigado pelos adereços. :)
jason saldo 26/02/09
5

Os dois que eu mais encontro e que podem ter um custo significativo em termos de desempenho são:

  • Usando cursores em vez de uma expressão baseada em conjunto. Eu acho que esse ocorre com frequência quando o programador está pensando de maneira processual.

  • Usando subconsultas correlacionadas, quando uma associação a uma tabela derivada pode fazer o trabalho.

Mitch Wheat
fonte
Eu concordo se você quer dizer o que eu acho que você quer dizer; embora uma subconsulta correlacionada seja um tipo de tabela derivada IIRC.
21868 dkretz
1
Uma tabela derivada é uma operação de conjunto, ao passo que um correlacionados corre subconsulta para cada linha em consulta externa, tornando-a menos eficiente (9 vezes de 10)
Mitch trigo
Há alguns anos, descobri, para minha surpresa, que o SQL S. de alguma forma é otimizado para lidar com consultas correlacionadas: para as mais simples, você obtém o mesmo plano de execução de uma consulta logicamente equivalente usando um JOIN! Além disso, as consultas correlatas que colocam o Oracle de joelhos são executadas apenas lentamente no SQL S.!
Joe Pineda
É por isso que eu sempre testei nos dois sentidos. E eu costumo tentar nos dois sentidos. Na prática, para o SQL Server de qualquer maneira, geralmente considero o sq correlacionado não mais lento.
21868 dkretz
3
POR FAVOR, entenda que uma subconsulta correlacionada e uma junção são IDENTICAS (na maioria dos casos). Nem sequer são coisas diferentes otimizadas entre si, mas apenas representações textuais diferentes da mesma operação.
21411 erikkallen
5

Colocar coisas em tabelas temporárias, especialmente as pessoas que alternam do SQL Server para o Oracle, costumam usar tabelas temporárias em excesso. Basta usar instruções de seleção aninhadas.

tuinstoel
fonte
5

Desenvolvedores que escrevem consultas sem ter uma boa idéia sobre o que torna os aplicativos SQL (consultas individuais e sistemas multiusuário) rápidos ou lentos. Isso inclui ignorância sobre:

  • estratégias de minimização de E / S física, uma vez que o gargalo da maioria das consultas é de E / S, não da CPU
  • impacto de diferentes tipos de acesso ao armazenamento físico (por exemplo, muitas E / S sequenciais serão mais rápidas que muitas pequenas E / S aleatórias, embora menos se o seu armazenamento físico for um SSD!)
  • como ajustar manualmente uma consulta se o DBMS produzir um plano de consulta ruim
  • como diagnosticar um desempenho ruim do banco de dados, como "depurar" uma consulta lenta e como ler um plano de consulta (ou EXPLAIN, dependendo do DBMS de sua escolha)
  • estratégias de bloqueio para otimizar a taxa de transferência e evitar conflitos em aplicativos multiusuários
  • importância do lote e outros truques para lidar com o processamento de conjuntos de dados
  • design de tabela e índice para melhor equilibrar espaço e desempenho (por exemplo, cobertura de índices, manutenção de índices pequenos sempre que possível, redução de tipos de dados para o tamanho mínimo necessário, etc.)
Justin Grant
fonte
3

Usando o SQL como um pacote ISAM (Método de Acesso Sequencial Indexado) glorificado. Em particular, aninhando cursores em vez de combinar instruções SQL em uma única instrução, embora maior. Isso também conta como 'abuso do otimizador', pois, na verdade, não há muito que o otimizador possa fazer. Isso pode ser combinado com declarações não preparadas para máxima ineficiência:

DECLARE c1 CURSOR FOR SELECT Col1, Col2, Col3 FROM Table1

FOREACH c1 INTO a.col1, a.col2, a.col3
    DECLARE c2 CURSOR FOR
        SELECT Item1, Item2, Item3
            FROM Table2
            WHERE Table2.Item1 = a.col2
    FOREACH c2 INTO b.item1, b.item2, b.item3
        ...process data from records a and b...
    END FOREACH
END FOREACH

A solução correta (quase sempre) é combinar as duas instruções SELECT em uma:

DECLARE c1 CURSOR FOR
    SELECT Col1, Col2, Col3, Item1, Item2, Item3
        FROM Table1, Table2
        WHERE Table2.Item1 = Table1.Col2
        -- ORDER BY Table1.Col1, Table2.Item1

FOREACH c1 INTO a.col1, a.col2, a.col3, b.item1, b.item2, b.item3
    ...process data from records a and b...
END FOREACH

A única vantagem da versão de loop duplo é que você pode identificar facilmente as quebras entre os valores na Tabela1 porque o loop interno termina. Isso pode ser um fator nos relatórios de quebra de controle.

Além disso, a classificação no aplicativo geralmente é um não-não.

Jonathan Leffler
fonte
O estilo, embora não seja essa sintaxe, é particularmente desenfreado no PHP na minha experiência.
dkretz
A sintaxe é realmente o IBM Informix-4GL - mas é claro o suficiente para não precisar de muita explicação (eu acho). E o estilo é galopante em muitos programas SQL - independentemente da linguagem de programação.
31416 Jonathan Leffler
Exceto pelo fato de você estar usando um antipadrão bem conhecido (junções implícitas) para ilustrar seu antipadrão, meio que derrota o ponto.
Johan
E é claro que o uso de cursores é um antipadrão SQl. Praticamente todos os cursores podem ser reescritos como operações baseadas em conjuntos. Os poucos que não podem são do tipo que somente DBAs com anos de experiência e que entendem como os internos da base de dados devem estar escrevendo. Nenhum desenvolvedor de aplicativos deve precisar escrever um cursor SQL.
HLGEM
3

Usando chaves primárias como substitutas para endereços de registros e usando chaves estrangeiras como substitutas para ponteiros incorporados nos registros.

Walter Mitty
fonte