web-dev-qa-db-fra.com

Conception de base de données pour la manipulation de 1 milliard de lignes et de compter

Nous recevons des données GPS en temps réel à une vitesse d'environ 5000 relations publiques. minute (à partir de 4 TCP serveurs). Chaque serveur utilise une seule connexion pour insérer les données et les données tampons entre les inserts. Toutes les 15 minutes environ, un service récupère ces données et le traite Dans les voyages. Une fois les voyages générés, les données GPS réelles ne sont généralement pas si importantes, uniquement si l'utilisateur souhaite voir l'itinéraire sur une carte.

Le problème est qu'il semble que la base de données ait du mal à suivre le taux de données insérées. Parfois, lorsque la charge augmente, l'heure d'insertion augmente soudainement radicalement (> 30 secondes), ce qui permet de faire tamponner plus de données, ce qui entraîne à son tour des inserts plus grands et une durée d'insertion plus longue.

J'espère avoir des commentaires sur la conception actuelle et certaines des idées que nous devons améliorer les performances et répondre à certaines de nos questions - et de toute autre astuce que les gens pourraient avoir!

Conception actuelle

Les données sont actuellement séparées en tableaux représentant une semaine et les données de plus d'un an sont archivées dans une base de données secondaire. Le tout est joint ensemble dans une vue modifiable, utilisée pour les inserts et les lectures.

conception de table

  • ID (PK, Diplensitionneur unique)
  • DeviceID (fk, int)
  • Personid (fk, int)
  • Véhiculeid (fk, int)
  • Tokenid (fk, int)
  • UTCTIME (PK, DateTime2 (3))
  • Latitude (flotteur)
  • Longitude (flotteur)
  • Vitesse (Smallint)
  • Rubrique (Smallint)
  • Satellites (Tinyint)
  • Iodata (varbinary (100))
  • Allumage (Tinyint)
  • UserInput (Tinyint)
  • CreateTimeTC (DateTime2 (3))

indices

  • DeviceID_CreateTimeTC_DESC
  • DeviceID_UTCTIME_DESC (regroupé)
  • Personid_utctime_desc
  • Tokenid_utctime_desc
  • Véhiculeid_utctime_desc

Chaque semaine occupe actuellement environ 10 Go, y compris des indices, et il existe actuellement environ 300 Go de données dans la base de données principale.

Les tables de données de la base de données principale ont leur propre groupe de fichiers avec 1 fichier, mais il se trouve sur le même disque que toutes les autres tables de la base de données principale. La base de données secondaire est sur un disque différent, mais sur la même machine.

Je pense que nous exécutons également une hebdomadaire d'index de reconstruction, lorsqu'une nouvelle partition de table (semaine) est prise en jeu. Aucun rétrécissement n'est effectué.

La machine est une HP à 8 cœurs avec une mémoire de 12 Go et le disque contenant la base de données principale est en cours d'exécution RAID 10.

idées

  • Limitez la quantité de données stockée dans la base de données principale à par exemple. max 1 mois. À tout le moins, il rendrait la base de données plus gérable pour la sauvegarde/la restauration, mais pourrions-nous nous attendre à voir une amélioration de la performance en faisant cela?
  • Créez 2 fichiers dans FileGroup pour les données actuelles et distribuez-les sur 2 partitions physiques différentes
  • Créez des bases de données maître-esclave tenant des données en cours, de sorte que les insertions et les lectures sont effectuées sur différentes bases de données.
  • Mettez des fichiers pour les données actuelles sur les disques SSD (reflétant une différence de performance avec les disques SSD?)

S'il vous plaît laissez-moi savoir si plus d'informations sont nécessaires. Il y a horriblement de nombreux facteurs influençant les performances et probablement de nombreuses façons de la modifier.

10
sondergard

5000 inserts par minute sont environ 83 inserts par seconde. Avec 5 index de 400 lignes physiques insérées par seconde. Si la charge de travail était en mémoire, cela ne poserait pas un problème même au plus petit des serveurs. Même s'il s'agissait d'un insert à ligne en rangée en utilisant la manière la plus inefficace que je puisse penser. 83 Les requêtes triviales par seconde ne sont tout simplement pas intéressantes d'un point de vue de la CPU.

Probablement, vous êtes lié à un disque. Vous pouvez vérifier cela en regardant des statistiques d'attente ou STATISTICS IO.

Vos requêtes touchent probablement beaucoup de pages différentes de sorte que la piscine tampon n'a pas de place pour toutes. Cela provoque des lectures de page fréquentes et probablement des écritures de disque aléatoire également.

Imaginez une table où vous n'enserez que physiquement à la fin à cause d'une clé toujours croissante. L'ensemble de travail serait une page: le dernier. Cela générerait séquentielle IO aussi bien que Wen L'écrivain paresseux ou le processus de point de contrôle écrit la "extrémité" de la table sur le disque.

Imaginez une table avec des insertions placées au hasard (exemple classique: une clé GUID). Ici, toutes pages sont le jeu de travail car une page aléatoire sera touchée pour chaque insertion. IOS sont aléatoires. C'est le pire des cas lorsqu'il s'agit de travailler ensemble.

Vous êtes au milieu. Vos index sont de la structure (SomeValue, SequentialDateTime). Le premier composant randomise partiellement la séquentialité fournie par la seconde. Je suppose qu'il y a plusieurs valeurs possibles pour "SomeValue" afin que vous ayez de nombreux points inserts placés au hasard dans vos index.

Vous dites que les données sont divisées en tables de 10 Go par semaine. C'est un bon point de départ, car l'ensemble de travail est maintenant délimité par 10 Go (sans tenir compte des lectures que vous pourriez faire). Avec 12 Go de mémoire de serveur, il est peu probable que toutes les pages pertinentes puissent rester en mémoire.

Si vous pouviez réduire la taille des "partitions" hebdomadaires ou augmenter la mémoire du serveur par un peu vous êtes probablement bien.

Je m'attendrais à ce que les insertions au début de la semaine soient plus rapides alors à la fin. Vous pouvez tester cette théorie sur un serveur DEV en exécutant une référence avec une certaine taille de données et réduisant progressivement la mémoire du serveur jusqu'à ce que vous voyiez le réservoir de performance.

Maintenant, même si tout se lit et écrit en mémoire, vous pourriez toujours avoir une page de chasse de page sale aléatoire io. Le seul moyen de se débarrasser de cela est d'écrire dans des positions co-localisées dans vos index. Si vous pouvez en tout cas convertir vos index pour utiliser (plus) clés séquentielles qui aideraient beaucoup.

En tant que solution rapide, j'ajouterais une couche tampon entre les clients et la table principale. Peut-être accumuler 15 minutes d'écriture dans une table de stadification et le rincer périodiquement. Cela élimine les pics de charge et utilise un plan plus efficace pour écrire sur la grande table.

8
usr