fundo
Sou estudante do primeiro ano do ensino médio e trabalho em meio período na pequena empresa de meu pai. Eu não tenho nenhuma experiência no desenvolvimento de aplicativos do mundo real. Eu escrevi scripts em Python, alguns cursos em C, mas nada como isso.
Meu pai tem uma pequena empresa de treinamento e atualmente todas as aulas são agendadas, gravadas e acompanhadas por um aplicativo da Web externo. Há um recurso de exportação / "relatórios", mas é muito genérico e precisamos de relatórios específicos. Não temos acesso ao banco de dados real para executar as consultas. Me pediram para configurar um sistema de relatórios personalizado.
Minha idéia é criar as exportações genéricas de CSV e importá-las (provavelmente com Python) para um banco de dados MySQL hospedado no escritório todas as noites, de onde eu possa executar as consultas específicas necessárias. Não tenho experiência em bancos de dados, mas entendo o básico. Eu li um pouco sobre criação de banco de dados e formas normais.
Podemos começar a ter clientes internacionais em breve, então quero que o banco de dados não exploda se / quando isso acontecer. Atualmente, também temos duas grandes corporações como clientes, com diferentes divisões (por exemplo, empresa-mãe da ACME, divisão de assistência médica da ACME, divisão de cuidados corporais da ACME)
O esquema que criei é o seguinte:
- Da perspectiva do cliente:
- Clientes é a tabela principal
- Os clientes estão vinculados ao departamento para o qual trabalham
- Os departamentos podem estar espalhados por um país: RH em Londres, Marketing em Swansea etc.
- Os departamentos estão vinculados à divisão de uma empresa
- As divisões estão vinculadas à controladora
- Da perspectiva das classes:
- Sessões é a tabela principal
- Um professor está vinculado a cada sessão
- Um statusid é fornecido para cada sessão. Por exemplo, 0 - Concluído, 1 - Cancelado
- As sessões são agrupadas em "pacotes" de tamanho arbitrário
- Cada pacote é atribuído a um cliente
- Sessões é a tabela principal
Eu "projetei" (mais como rabiscado) o esquema em um pedaço de papel, tentando mantê-lo normalizado no terceiro formulário. Depois, pluguei-o no MySQL Workbench e tudo ficou bonito para mim:
( Clique aqui para gráficos em tamanho normal )
(fonte: maian.org )
Consultas de exemplo que estarei executando
- Quais clientes com crédito ainda estão inativos (aqueles sem aula agendada no futuro)
- Qual é a taxa de participação por cliente / departamento / divisão (medida pelo ID do status em cada sessão)
- Quantas aulas um professor teve em um mês
- Sinalizar clientes com baixa taxa de participação
- Relatórios personalizados para departamentos de RH com taxas de participação de pessoas em sua divisão
Questões)
- Isso é superengenharia ou estou seguindo o caminho certo?
- A necessidade de ingressar em várias tabelas para a maioria das consultas resultará em um grande impacto no desempenho?
- Eu adicionei uma coluna 'dura-sessão' aos clientes, pois provavelmente será uma consulta comum. É uma boa ideia ou devo manter o banco de dados estritamente normalizado?
Obrigado pelo seu tempo
fonte
divisions
tem coluna chamadadivisionid
. Você não acha isso redundante? Apenas citeid
. também os nomes das suas tabelas, incluindo_has_
: eu removeria isso e nomearia apenas por exemplocities_departments
. suasDATETIME
colunas devem ser do tipo, aTIMESTAMP
menos que sejam valores de entrada do usuário. Eu acho que é uma boa ideia ter as tabelascities
ecountries
. você pode ter problemas para limitar as tabelas a uma únicastatus
. considerar o uso de umINT
e realizar comparações bit a bit em ele- assim que você pode segurar mais significado láRespostas:
Mais algumas respostas para suas perguntas:
1) Você está praticamente no alvo para alguém que está abordando um problema como este pela primeira vez. Penso que os indicadores de outras pessoas sobre essa questão até agora praticamente a cobrem. Bom trabalho!
2 e 3) O desempenho atingido dependerá em grande parte de ter e otimizar os índices corretos para suas consultas / procedimentos específicos e, mais importante, do volume de registros. A menos que você esteja falando de mais de um milhão de registros em suas tabelas principais, você parece estar no caminho de ter um design suficientemente mainstream para que o desempenho não seja um problema em hardware razoável.
Dito isto, e isso se relaciona à sua pergunta 3, com o início, você provavelmente não deveria se preocupar muito com desempenho ou hiper-sensibilidade à ortodoxia da normalização aqui. Este é um servidor de relatório que você está construindo, não um back-end de aplicativo baseado em transações, que teria um perfil muito diferente em relação à importância do desempenho ou da normalização. Um banco de dados que faz backup de um aplicativo de inscrição e agendamento ao vivo deve estar atento às consultas que levam segundos para retornar dados. Não apenas uma função de servidor de relatório tem mais tolerância para consultas complexas e demoradas, mas as estratégias para melhorar o desempenho são muito diferentes.
Por exemplo, em um ambiente de aplicativo baseado em transações, suas opções de melhoria de desempenho podem incluir a refatoração de procedimentos armazenados e estruturas de tabela até o enésimo grau, ou o desenvolvimento de uma estratégia de armazenamento em cache para pequenas quantidades de dados solicitados com frequência. Em um ambiente de relatório, você certamente pode fazer isso, mas pode ter um impacto ainda maior no desempenho, introduzindo um mecanismo de captura instantânea em que um processo agendado é executado e armazena relatórios pré-configurados e seus usuários acessam os dados da captura instantânea sem estresse na camada db por solicitação.
Tudo isso é um discurso longo para ilustrar que os princípios e truques de design que você emprega podem diferir, dado o papel do banco de dados que você está criando. Espero que seja útil.
fonte
Você tem a ideia certa. No entanto, você pode limpá-lo e remover algumas das tabelas de mapeamento (possui *).
O que você pode fazer é, na tabela Departamentos, adicionar CityId e DivisionId.
Além disso, acho que está tudo bem ...
fonte
As únicas mudanças que eu faria são:
1- Altere seu VARCHAR para NVARCHAR; se você estiver indo para o exterior, poderá desejar um código único.
2- Altere os IDs int para GUIDs (uniqueidentifier), se possível (pode ser apenas minha preferência pessoal). Supondo que você chegue ao ponto em que você possui vários ambientes (dev / test / staging / prod), convém migrar dados de um para o outro. Ter IDs de GUID torna isso significativamente mais fácil.
3- Três camadas para a sua empresa -> Divisão -> Estrutura do departamento pode não ser suficiente. Agora, isso pode ser um excesso de engenharia, mas você pode generalizar essa hierarquia para suportar n níveis de profundidade. Isso tornará algumas de suas consultas mais complexas, de modo que talvez não valha a pena. Além disso, pode ser que qualquer cliente que tenha mais camadas possa ser facilmente "empacotado" nesse modelo.
4- Você também tem um Status na Tabela do Cliente que é um VARCHAR e não possui um link para a tabela Status. Eu esperaria um pouco mais de clareza quanto ao que o Status do Cliente representa.
fonte
Não. Parece que você está projetando com um bom nível de detalhe.
Penso que Países e Empresas são realmente a mesma entidade em seu projeto, assim como Cidades e Divisões. Eu me livraria das tabelas Países e Cidades (e Cities_Has_Departments) e, se necessário, adicionaria um sinalizador booleano IsPublicSector à tabela Companies (ou uma coluna CompanyType se houver mais opções do que simplesmente Setor Privado / Setor Público).
Além disso, acho que há um erro no uso da tabela Departamentos. Parece que a tabela Departamentos serve como referência aos vários tipos de departamentos que cada divisão de clientes pode ter. Nesse caso, deve ser chamado de DepartmentTypes. Mas seus clientes (que são, presumo, participantes) não pertencem a um TIPO de departamento, eles pertencem a uma instância de departamento real de uma empresa. Como está agora, você saberá que um determinado cliente pertence a um departamento de RH em algum lugar, mas não a qual!
Em outras palavras, os Clientes devem estar vinculados à tabela que você chama de Divisions_Has_Departments (mas que eu chamaria simplesmente de Departamentos). Se for assim, você deve recolher Cidades em Divisões, conforme discutido acima, se desejar usar a integridade referencial padrão no banco de dados.
fonte
A propósito, vale a pena notar que, se você já está gerando CSVs e deseja carregá-los em um banco de dados mySQL, LOAD DATA LOCAL INFILE é seu melhor amigo: http://dev.mysql.com/doc/refman/5.1/ pt-br / load-data.html . Também vale a pena examinar o Mysqlimport, e é uma ferramenta de linha de comando que é basicamente um bom invólucro em torno do carregamento de dados infile.
fonte
A maioria das coisas já foi dita, mas sinto que posso acrescentar uma coisa: é bastante comum que desenvolvedores mais jovens se preocupem com o desempenho um pouco demais, e sua pergunta sobre a junção de tabelas parece ir nessa direção. Este é um anti-padrão de desenvolvimento de software chamado ' Otimização prematura '. Tente banir esse reflexo da sua mente :)
Mais uma coisa: você acredita que realmente precisa das tabelas de 'cidades' e 'países'? Ter uma coluna 'cidade' e 'país' na tabela de departamentos é suficiente para seus casos de uso? Por exemplo, seu aplicativo precisa listar departamentos por cidade e cidades por país?
fonte
Após comentários com base na função de especialista em Business Intelligence / Reporting e gerente de estratégia / planejamento:
Eu concordo com a direção de Larry acima. IMHO, não é muito exagerado, algumas coisas parecem um pouco fora do lugar. Para simplificar, eu marcaria o cliente diretamente em uma ID da empresa, Descrição do departamento, Descrição da divisão, ID do tipo de departamento, ID do tipo de divisão. Use o ID do tipo de departamento e o ID do tipo de divisão como referências às tabelas de pesquisa e aos campos internos de relatório / análise para obter consistência a longo prazo.
A tabela de pacotes contém a coluna "Crédito". Isso não deveria estar realmente vinculado à tabela da base do cliente; portanto, se houver muitos pacotes, você poderá ver quanto crédito resta para as classes futuras? O aplicativo pode cuidar do cálculo e armazená-lo centralmente na tabela Cliente.
As informações da empresa podem usar muitos outros campos, incluindo o endereço óbvio / telefone / etc. em formação. Eu também estaria preparado para adicionar as colunas D&B "DUNs" (Site / Filial / Ultimate) a longo prazo, Dun e Bradstreet (D&B) têm um enorme catálogo de empresas e você encontrará mais tarde, no futuro, suas informações são muito úteis para relatórios / análises. Isso resolverá o problema de divisão múltipla que você mencionou e permitirá que você monte sua hierarquia para sub / division / branches / etc. de grandes corpos.
Você não menciona quantos registros com os quais você trabalhará, o que poderia implicar em se preparar para uma grande iniciativa de desenvolvimento que poderia ter sido feita mais rapidamente e com muito menos dores de cabeça com o software de "relatório" pré-empacotado. Se você não está lidando com um grande banco de dados (<65000) de linhas, verifique se o MS-Access, OpenOffice (Base) ou soluções relacionadas de relatórios / aplicativos de desenvolvimento não conseguiram. Eu mesmo uso o software APEX gratuito da Oracle, ele vem com o banco de dados gratuito Oracle XE, basta baixá-lo do site.
FYI - insight de relatórios: para bancos de dados grandes, normalmente você tem duas instâncias de banco de dados a) banco de dados de transações para registrar cada registro detalhado. b) banco de dados de relatórios (data mart / data warehouse) alojado em uma máquina separada. Para obter mais informações, pesquise no Google o esquema Star e o esquema Snowflake.
Saudações.
fonte
Quero abordar apenas a preocupação de que a associação a várias tabelas apresentará um impacto no desempenho. Não tenha medo de normalizar porque você terá que fazer junções. As junções são normais e esperadas em bases de dados relacionais e são projetadas para lidar com elas também. Você precisará definir os relacionamentos PK / FK (para integridade dos dados, é importante considerar isso no design), mas em muitos bancos de dados os FKs não são indexados automaticamente. Como eles serão usados nas junções, você definitivamente desejará começar indexando o FKS. Os PKs geralmente obtêm um índice na criação, pois precisam ser únicos. É verdade que o design do datawarehouse reduz o número de junções, mas geralmente não se chega ao ponto de data warehouse até que haja milhões de registros necessários para serem acessados em um relatório. Mesmo assim, quase todos os data warehouses começam com um banco de dados transacional para coletar os dados em tempo real e, em seguida, os dados são movidos para o armazém em um horário (noturno ou mensal ou qualquer que seja a necessidade da empresa). Portanto, este é um bom começo, mesmo se você precisar projetar um data warehouse mais tarde para melhorar o desempenho do relatório.
Devo dizer que seu design é impressionante para um aluno do primeiro ano do ensino médio.
fonte
Não é exagerado, é assim que eu abordaria o problema. A associação é boa, não haverá muito impacto no desempenho (é completamente necessário, a menos que você des Normalize o banco de dados, o que não é recomendado!). Para status, veja se você pode usar um tipo de dados enum para otimizar essa tabela.
fonte
Eu trabalhei no domínio treinamento / escola e pensei em ressaltar que geralmente há uma relação M: 1 entre o que você chama de "sessões" (instâncias de um determinado curso) e o próprio curso. Em outras palavras, seu catálogo oferece o curso ("espanhol 101" ou o que for), mas você pode ter duas instâncias diferentes durante um único semestre (Tu-Th ministrado por Smith, Wed-Fri ministrado por Jones).
Fora isso, parece um bom começo. Aposto que você descobrirá que o domínio do cliente (gráficos que levam a "clientes") é mais complexo do que o modelado, mas não exagere até que você tenha alguns dados reais para guiá-lo.
fonte
Algumas coisas vieram à mente:
As mesas pareciam estar voltadas para os relatórios, mas não realmente administrando o negócio. Eu acho que quando um cliente se inscreve, há essencialmente um pedido sendo feito para o cliente participando de uma lista de sessões, e esse pedido pode ser para vários funcionários em uma empresa. Parece que uma tabela de "pedidos" estaria realmente no centro do seu sistema e direcionaria sua captura de dados e eventuais relatórios. (Compare os documentos em papel que você está usando para administrar os negócios com o design do banco de dados para verificar se há uma correspondência lógica.)
As empresas geralmente não têm divisões. Às vezes, os funcionários alteram divisões / departamentos, talvez até no meio da sessão. Às vezes, as empresas adicionam / excluem / renomeiam divisões / departamentos. Certifique-se de que o possível conteúdo em tempo real de alteração de suas tabelas não torne difícil o relatório / agrupamento subsequente. Com tantos dados de contato divididos em tantas tabelas, talvez você precise impor uma validação muito estrita da entrada de dados para manter seus relatórios significativos e inclusivos. Por exemplo, quando um novo cliente é adicionado, verifique se a empresa / divisão / departamento / cidade corresponde aos mesmos valores que seus colegas de trabalho.
O conceito de "pacotes" não está claro.
Como você indica que é uma pequena empresa, seria surpreendente se o desempenho fosse um problema, considerando a velocidade e a capacidade das máquinas atuais.
fonte