Ich stieß auf genau diese Frage und entschied, dass ich ein kleines Benchmark ausführen sollte, um die Geschwindigkeitsunterschiede zu quantifizieren. Die Ergebnisse haben mich überrascht. Ich möchte meine Erfahrung mit dieser Art von Frage posten.
Wie bei einigen der anderen Poster hier mein Gedanke war, dass die Datenbank-Ebene würde die Sortierung schneller tun, weil sie angeblich für diese Art von Dingen eingestellt sind. @Alex hat darauf hingewiesen, dass die Datenbank schneller ist, wenn die Datenbank bereits einen Index für die Sortierung enthält. Ich wollte die Frage beantworten, welche rohe Sortierung bei nicht indizierten Sortierungen schneller ist. Beachte, ich sagte schneller, nicht einfacher. Ich denke, in vielen Fällen ist die Arbeit einfacher und weniger fehleranfällig.
Meine Hauptannahme war, dass die Sortierung in den Hauptspeicher passen würde. Nicht alle Probleme werden hier passen, aber eine gute Anzahl. Für nicht genügend Speicher kann es gut sein, dass Datenbanken hier leuchten, obwohl ich das nicht getestet habe. Im Fall von In-Memory-Sortierungen übertraf alles von Java/C/C++ Mysql in meinem informellen Benchmark, wenn man es so nennen könnte.
Ich wünschte, ich hätte mehr Zeit gehabt, um die Datenbank-Ebene im Vergleich zur Anwendungsschicht, aber leider andere Aufgaben genannt gründlich zu vergleichen. Trotzdem konnte ich nicht anders, als diese Notiz für andere aufzuzeichnen, die diese Straße entlangfahren.
Als ich diesen Weg begann, sah ich mehr Hürden. Soll ich die Datenübertragung vergleichen? Wie? Kann ich die Zeit vergleichen, um db vs Zeit zu lesen, um eine flache Datei in Java zu lesen? Wie kann man die Sortierzeit gegenüber der Datentransferzeit gegenüber der Zeit isolieren, um die Datensätze zu lesen? Mit diesen Fragen hier war die Methodik und Timing-Nummern, die ich gefunden habe.
Alle Zeiten in ms, sofern nicht anders
geschrieben
Alle Sortierroutinen waren die von der Sprache zur Verfügung gestellt Standardwerte (diese sind gut genug für gelegentliche sortierte Daten)
Alle Kompilation war mit einem typischen „Release-Profil“ via netbeans ohne Anpassung gewählt, es sei denn
Alle Tests für mysql sonst
geschrieben verwendet das folgende Schema
mysql> CREATE TABLE test_1000000
(
pk bigint(11) NOT NULL,
float_value DOUBLE NULL,
bigint_value bigint(11) NULL,
PRIMARY KEY (pk)
) Engine MyISAM;
mysql> describe test_1000000;
+--------------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------+------+-----+---------+-------+
| pk | bigint(11) | NO | PRI | NULL | |
| float_value | double | YES | | NULL | |
| bigint_value | bigint(11) | YES | | NULL | |
+--------------+------------+------+-----+---------+-------+
Hier ist ein kleiner Ausschnitt, um die DB zu füllen. Es kann einfacher Weise sein, aber das ist, was ich tat:
public static void BuildTable(Connection conn, String tableName, long iterations) {
Random ran = new Random();
Math.random();
try {
long epoch = System.currentTimeMillis();
for (long i = 0; i < iterations; i++) {
if (i % 100000 == 0) {
System.out.println(i + " next 100k");
}
PerformQuery(conn, tableName, i, ran.nextDouble(), ran.nextLong());
}
} catch (Exception e) {
logger.error("Caught General Exception Error from main " + e);
}
}
MYSQL Direkt CLI Ergebnisse:
select * from test_10000000 order by bigint_value limit 10;
10 rows in set (2.32 sec)
Diese Zeiten waren etwas schwierig, da die einzige Info, das ich die Zeit nach der Hinrichtung berichtet hatte, war des Befehls.
von mysql-Eingabeaufforderung für 10000000 Elemente es etwa 2.1 bis 2.4 ist entweder für bigint_value Sortieren oder float_value
Java JDBC MySQL-Aufruf (eine ähnliche Leistung zu Art, die aus mysql cli tun)
public static void SortDatabaseViaMysql(Connection conn, String tableName) {
try {
Statement stmt = conn.createStatement();
String cmd = "SELECT * FROM " + tableName + " order by float_value limit 100";
ResultSet rs = stmt.executeQuery(cmd);
} catch (Exception e) {
}
}
Fünf Läufe:
Java Sort Zufallszahlen beim Fliegen generieren (war eigentlich langsamer als das Lesen der Datenträger-IO).Einsatzzeit ist die Zeit, Zufallszahlen zu erzeugen, und füllen Sie das Array
Aufruf wie
JavaSort(10,10000000);
Timing-Ergebnisse:
assignment time 331 sort time 1139
assignment time 324 sort time 1037
assignment time 317 sort time 1028
assignment time 319 sort time 1026
assignment time 317 sort time 1018
assignment time 325 sort time 1025
assignment time 317 sort time 1024
assignment time 318 sort time 1054
assignment time 317 sort time 1024
assignment time 317 sort time 1017
Diese Ergebnisse zum Lesen einer Datei von Doppel im Binär-Modus waren
assignment time 4661 sort time 1056
assignment time 4631 sort time 1024
assignment time 4733 sort time 1004
assignment time 4725 sort time 980
assignment time 4635 sort time 980
assignment time 4725 sort time 980
assignment time 4667 sort time 978
assignment time 4668 sort time 980
assignment time 4757 sort time 982
assignment time 4765 sort time 987
Eine Pufferübertragung führt zu viel schnelleren Laufzeiten
assignment time 77 sort time 1192
assignment time 59 sort time 1125
assignment time 55 sort time 999
assignment time 55 sort time 1000
assignment time 56 sort time 999
assignment time 54 sort time 1010
assignment time 55 sort time 999
assignment time 56 sort time 1000
assignment time 55 sort time 1002
assignment time 56 sort time 1002
C und C++ Timing-Ergebnisse (unten Quelle sehen)
Debug Profil mit qsort
assignment 0 seconds 110 milliseconds Time taken 2 seconds 340 milliseconds
assignment 0 seconds 90 milliseconds Time taken 2 seconds 340 milliseconds
assignment 0 seconds 100 milliseconds Time taken 2 seconds 330 milliseconds
assignment 0 seconds 100 milliseconds Time taken 2 seconds 340 milliseconds
assignment 0 seconds 100 milliseconds Time taken 2 seconds 330 milliseconds
assignment 0 seconds 100 milliseconds Time taken 2 seconds 340 milliseconds
assignment 0 seconds 90 milliseconds Time taken 2 seconds 340 milliseconds
assignment 0 seconds 100 milliseconds Time taken 2 seconds 330 milliseconds
assignment 0 seconds 100 milliseconds Time taken 2 seconds 340 milliseconds
assignment 0 seconds 100 milliseconds Time taken 2 seconds 330 milliseconds
Freisetzungsprofil mit qsort
assignment 0 seconds 100 milliseconds Time taken 1 seconds 600 milliseconds
assignment 0 seconds 90 milliseconds Time taken 1 seconds 600 milliseconds
assignment 0 seconds 90 milliseconds Time taken 1 seconds 580 milliseconds
assignment 0 seconds 90 milliseconds Time taken 1 seconds 590 milliseconds
assignment 0 seconds 80 milliseconds Time taken 1 seconds 590 milliseconds
assignment 0 seconds 90 milliseconds Time taken 1 seconds 590 milliseconds
assignment 0 seconds 90 milliseconds Time taken 1 seconds 600 milliseconds
assignment 0 seconds 90 milliseconds Time taken 1 seconds 590 milliseconds
assignment 0 seconds 90 milliseconds Time taken 1 seconds 600 milliseconds
assignment 0 seconds 90 milliseconds Time taken 1 seconds 580 milliseconds
Freisetzungsprofil std :: Sortieren (a, a + ARRAY_SIZE);
assignment 0 seconds 100 milliseconds Time taken 0 seconds 880 milliseconds
assignment 0 seconds 90 milliseconds Time taken 0 seconds 870 milliseconds
assignment 0 seconds 90 milliseconds Time taken 0 seconds 890 milliseconds
assignment 0 seconds 120 milliseconds Time taken 0 seconds 890 milliseconds
assignment 0 seconds 90 milliseconds Time taken 0 seconds 890 milliseconds
assignment 0 seconds 90 milliseconds Time taken 0 seconds 880 milliseconds
assignment 0 seconds 90 milliseconds Time taken 0 seconds 900 milliseconds
assignment 0 seconds 90 milliseconds Time taken 0 seconds 890 milliseconds
assignment 0 seconds 100 milliseconds Time taken 0 seconds 890 milliseconds
assignment 0 seconds 150 milliseconds Time taken 0 seconds 870 milliseconds
Freisetzungsprofil Zufallsdaten aus der Datei lesen und mit std :: sort (a, a + ARRAY_SIZE)
assignment 0 seconds 50 milliseconds Time taken 0 seconds 880 milliseconds
assignment 0 seconds 40 milliseconds Time taken 0 seconds 880 milliseconds
assignment 0 seconds 50 milliseconds Time taken 0 seconds 880 milliseconds
assignment 0 seconds 50 milliseconds Time taken 0 seconds 880 milliseconds
assignment 0 seconds 40 milliseconds Time taken 0 seconds 880 milliseconds
Im Folgenden ist der Quellcode verwendet. Hoffentlich minimale Bugs :)
Java-Quelle Beachten Sie, dass innerhalb von JavaSort die runCode und writeFlag angepasst werden müssen, je nachdem, was Sie möchten. Beachten Sie auch, dass die Speicherzuweisung geschieht in der for-Schleife (also Testen GC, aber ich habe keinen nennenswerten Unterschied sehen die Zuweisung außerhalb der Schleife zu bewegen)
public static void JavaSort(int iterations, int numberElements) {
Random ran = new Random();
Math.random();
int runCode = 2;
boolean writeFlag = false;
for (int j = 0; j < iterations; j++) {
double[] a1 = new double[numberElements];
long timea = System.currentTimeMillis();
if (runCode == 0) {
for (int i = 0; i < numberElements; i++) {
a1[i] = ran.nextDouble();
}
}
else if (runCode == 1) {
//do disk io!!
try {
DataInputStream in = new DataInputStream(new FileInputStream("MyBinaryFile.txt"));
int i = 0;
//while (in.available() > 0) {
while (i < numberElements) { //this should be changed so that I always read in the size of array elements
a1[i++] = in.readDouble();
}
}
catch (Exception e) {
}
}
else if (runCode == 2) {
try {
FileInputStream stream = new FileInputStream("MyBinaryFile.txt");
FileChannel inChannel = stream.getChannel();
ByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
//int[] result = new int[500000];
buffer.order(ByteOrder.BIG_ENDIAN);
DoubleBuffer doubleBuffer = buffer.asDoubleBuffer();
doubleBuffer.get(a1);
}
catch (Exception e) {
}
}
if (writeFlag) {
try {
DataOutputStream out = new DataOutputStream(new FileOutputStream("MyBinaryFile.txt"));
for (int i = 0; i < numberElements; i++) {
out.writeDouble(a1[i]);
}
} catch (Exception e) {
}
}
long timeb = System.currentTimeMillis();
Arrays.sort(a1);
long timec = System.currentTimeMillis();
System.out.println("assignment time " + (timeb - timea) + " " + " sort time " + (timec - timeb));
//delete a1;
}
}
C/C++ Quelle
#include <iostream>
#include <vector>
#include <algorithm>
#include <fstream>
#include <cstdlib>
#include <ctime>
#include <cstdio>
#include <math.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define ARRAY_SIZE 10000000
using namespace std;
int compa(const void * elem1, const void * elem2) {
double f = *((double*) elem1);
double s = *((double*) elem2);
if (f > s) return 1;
if (f < s) return -1;
return 0;
}
int compb (const void *a, const void *b) {
if (*(double **)a < *(double **)b) return -1;
if (*(double **)a > *(double **)b) return 1;
return 0;
}
void timing_testa(int iterations) {
clock_t start = clock(), diffa, diffb;
int msec;
bool writeFlag = false;
int runCode = 1;
for (int loopCounter = 0; loopCounter < iterations; loopCounter++) {
double *a = (double *) malloc(sizeof (double)*ARRAY_SIZE);
start = clock();
size_t bytes = sizeof (double)*ARRAY_SIZE;
if (runCode == 0) {
for (int i = 0; i < ARRAY_SIZE; i++) {
a[i] = rand()/(RAND_MAX + 1.0);
}
}
else if (runCode == 1) {
ifstream inlezen;
inlezen.open("test", ios::in | ios::binary);
inlezen.read(reinterpret_cast<char*> (&a[0]), bytes);
}
if (writeFlag) {
ofstream outf;
const char* pointer = reinterpret_cast<const char*>(&a[0]);
outf.open("test", ios::out | ios::binary);
outf.write(pointer, bytes);
outf.close();
}
diffa = clock() - start;
msec = diffa * 1000/CLOCKS_PER_SEC;
printf("assignment %d seconds %d milliseconds\t", msec/1000, msec % 1000);
start = clock();
//qsort(a, ARRAY_SIZE, sizeof (double), compa);
std::sort(a, a + ARRAY_SIZE);
//printf("%f %f %f\n",a[0],a[1000],a[ARRAY_SIZE-1]);
diffb = clock() - start;
msec = diffb * 1000/CLOCKS_PER_SEC;
printf("Time taken %d seconds %d milliseconds\n", msec/1000, msec % 1000);
free(a);
}
}
/*
*
*/
int main(int argc, char** argv) {
printf("hello world\n");
double *a = (double *) malloc(sizeof (double)*ARRAY_SIZE);
//srand(1);//change seed to fix it
srand(time(NULL));
timing_testa(5);
free(a);
return 0;
}
Manchmal ist es nicht eine einfache Technologie-Wahl, in meinem Fall ist die db sehr beschäftigt und wird wahrscheinlich zum Engpass, so dass ich HAVA im Speicher sortieren. – shellbye