Question

Imaginez que nous ayons un ensemble d'entités dont chacune a son état: libre, occupé ou cassé. L'État est spécifié pour une journée, par exemple, aujourd'hui au 2011-05-17, une entité E1 est gratuite et demain le 2011-05-18 il est occupé.

Il est nécessaire de stocker ~ 10 ^ 5 entités pendant 1000 jours. Quelle est la meilleure façon de le faire?

Je pense à 2 options:

  • représenter chaque jour comme un personnage "0", "1" ou "2" et stocker pour chaque entité une chaîne de 1000 caractères
  • Conservez chaque jour avec l'état d'entité d'affilée, c'est-à-dire 1000 lignes pour une entité

La requête la plus importante pour ces données est la suivante: Étant donné la date de début et la date de fin, identifier les entités gratuites.

Les performances sont plus prioritaires que le stockage.

Toutes les suggestions et commentaires sont les bienvenus.

Était-ce utile?

La solution

Créez une seule table pour maintenir vos données. Créez le tableau avec un ID, une date, un nom d'entité et huit champs booléens. SQL Server 2008 m'a donné le code ci-dessous pour le tableau:

CREATE TABLE [dbo].[EntityAvailability](
[EA_Id] [int] IDENTITY(1,1) NOT NULL,
[EA_Date] [date] NOT NULL,
[EA_Entity] [nchar](10) NOT NULL,
[EA_IsAvailable] [bit] NOT NULL,
[EA_IsUnAvailable] [bit] NOT NULL,
[EA_IsBroken] [bit] NOT NULL,
[EA_IsLost] [bit] NOT NULL,
[EA_IsSpare1] [bit] NOT NULL,
[EA_IsSpare2] [bit] NOT NULL,
[EA_IsSpare3] [bit] NOT NULL,
[EA_IsActive] [bit] NOT NULL,
 CONSTRAINT [IX_EntityAvailability_Id] UNIQUE NONCLUSTERED 
(
    [EA_Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
END
GO

IF NOT EXISTS (SELECT * FROM sys.indexes WHERE object_id = OBJECT_ID(N'[dbo].[EntityAvailability]') AND name = N'IXC_EntityAvailability_Date')
CREATE CLUSTERED INDEX [IXC_EntityAvailability_Date] ON [dbo].[EntityAvailability] 
(
    [EA_Date] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

L'index en cluster à la date fonctionnera le mieux pour vos recherches de plages. N'autorisez jamais les recherches sans plage de dates et il n'y aura pas besoin d'index autres que l'index en cluster. Les champs booléens autorisent huit situations en utilisant un seul octet. La taille des lignes pour ce tableau est de 35 octets. 230 lignes tiendront sur une page. Vous avez déclaré que vous aviez besoin de stocker 10 ^ 5 entités pendant 1000 jours, soit 100 millions. Cent millions de lignes occuperont 434 782 pages 8K ou environ 3 concerts.

Installez le tableau sur un SSD et vous êtes prêt à partir.

Autres conseils

La meilleure façon est d'essayer d'abord l'option plus simple et plus flexible (c'est-à-dire stocker chaque jour dans sa propre rangée) et concevoir une méthode alternative sophistiquée si les performances sont insatisfaisantes. Évitez l'optimisation prématurée.

10 ^ 8 Rows n'est pas un si gros problème pour votre base de données moyenne sur un serveur de produits de base de nos jours. Mettez un index à la date, et je parierais que les requêtes de plage ("Date de début et date de fin donnée ...") fonctionnera très bien.

Les raisons pour lesquelles je prétends que cela est à la fois plus simple et plus flexible que l'idée de stocker une chaîne de 1000 caractères est:

  • Vous devrez traiter cela en code, et ce code ne serait pas aussi simple à comprendre que le code qui interroge les enregistrements DB qui contiennent la date et l'état.
  • Selon le moteur de la base de données, les chaînes de 1000 caractères peuvent être des blobs qui sont stockées en dehors de l'enregistrement. Cela les rend moins efficaces.
  • Que se passe-t-il si vous avez soudainement besoin de 2 000 jours au lieu de 1 000? Commencez à mettre à jour toutes les lignes et le code qui les traite? C'est beaucoup plus de travail que de simplement changer votre requête.
  • Que se passe-t-il lorsque vous êtes ensuite demandé de stocker des informations supplémentaires par dossier quotidien, ou que vous devez changer la granularité (passer de jours à heures par exemple)?

Selon que les entités soient plus souvent gratuites ou non seulement stockent les dates lorsqu'une entité est gratuite ou non.

En supposant que vous stockez les dates lorsque l'entité n'est pas gratuite, la recherche est là où la date de début <= date et end_date> = date et toute correspondance de ligne qui signifie que l'entité n'est pas gratuite pour cette période

Il semble que vous puissiez être sur la bonne voie et je dirais en raison du nombre d'enregistrements et de l'accent mis sur les performances que vous gardez le schéma aussi dénormalisé que possible. Moins vous devez faire de jointures pour déterminer les entités libres ou occupées, mieux c'est.

J'irais largement pour un schéma star de Kimball (http://en.wikipedia.org/wiki/Star_Schema) de type Structure avec trois tables (initialement)

  • Facture (FK Kstatus, Kdate)
  • Dimstatus (pk kstatus)
  • Dimdate (pk kdate)

Cela peut être chargé tout simplement (DIMS, suivi d'abord des faits), et interrogé également très simplement. Les performances peuvent être optimisées par une indexation appropriée.

Un grand avantage de cette conception est qu'il est très extensible; Si vous souhaitez augmenter la plage de dates ou augmenter le nombre d'états valides, il est trivial à étendre.

D'autres dimensions pourraient être sensiblement ajoutées, par exemple, la dimentité qui pourrait avoir des informations plus riches qui donnent des informations catégorielles qui sont intéressantes pour trancher / dés entiner vos entités.

Le dimdate est normalement enrichi en ajoutant Dayno, Monthno, aswo, Dayofweek, WeekendFlag, WeekdayFlag, Publicholidayflag. Ceux-ci permettent de effectuer des analyses très intéressantes.

Comme @Elad le demande, que serait AHPPEN si vous ajoutez des informations en temps basées sur le temps, cela peut également être infirmier par une dimension sombre ayant un enregistrement par heure ou par minute.

Toutes mes excuses pour ma dénomination, car je n'ai pas une bonne compréhension de vos données. Étant donné plus de temps, je pourrais en trouver de meilleurs!

enter image description here

Pour obtenir des entités gratuites à une date, vous pouvez essayer:

select
      e.EntityName
    , s.StateName
    , x.ValidFrom
from EntityState as x
join Entity      as e on e.EntityId = x.EntityId
join State       as s on s.StateID  = x.StateID
where StateName = 'free'
  and x.ValidFrom = ( select max(z.ValidFrom)
                      from EntityState as z
                      where z.EntityID   = x.EntityID
                        and z.ValidFrom <= your_date_here )
;

Remarque: assurez-vous que vous stockez uniquement les changements d'état dans EntityState table.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top