In diesem Beitrag geht es hauptsächlich um die Verwendung der SQL-Funktionen von JMP, aber auch um XML, Linux und MythTV.
Dokument zum SQL-Abfragegenerator: https://www.jmp.com/support/help/14/query-builder.shtml#
MythTV https://www.mythtv.org/ ist ein Open-Source-Programm (TANSTAAFL), das Over-the-Air-TV-Sendungen mit einer Tuner-Karte in einem PC aufzeichnen kann (und noch ein paar andere Sachen). Es ist eine großartige Möglichkeit, etwas über Linux und MySQL/MariaDB zu lernen und das Fernsehen zu vermeiden. Die Implementierung verwendet zwei Computer, ein Backend (oder mehrere), das die Aufzeichnung durchführt, und ein Frontend (oder mehrere), das die Überwachung durchführt. Eine SQL-Datenbank verfolgt, was aufgezeichnet werden soll und was aufgezeichnet wurde.
https://code.mythtv.org/trac/ticket/12974#no1 beschreibt einen Grund, warum es viele wirklich alte, wirklich große Dateien auf der MythTV-Backend-Festplatte gibt, die im MythTV-Frontend nicht sichtbar sind. Es besagt, dass es einen MythTV-Bug um das Datenbankfeld deletepending gibt, der verhindert, dass die Datei gelöscht wird, wenn MythTV zwischen dem Setzen des Felds und dem Löschen der Datei abstürzt.
Zum Beispiel mit Linux ls Befehl zum Auflisten einiger Dateien, hier ist ein 3-GB-Beispiel (es ist Dezember 2019; nur etwa zwei Wochen an Dateien passen auf die 3T-Festplatte; diese Dateien sollten längst verschwunden sein.)
-rw-r--r-- 1 mythtv mythtv 3.1G 21. März 2018 1051_20180321073000.ts
Oder, nachdem Sie einen Datenbankimport durchgeführt haben,
JMP data table imported from database showing old, large filesJMP data table imported from database showing old, large filesJMP data table imported from database showing old, large filesJMP data table imported from database showing old, large filesAus Datenbank importierte JMP-Datentabelle mit alten, großen Dateien
Der Datenbankimport erscheint sinnvoll; Es stellt Spalten (oder Felder) mit verwandten Werten nebeneinander und kombiniert Informationen aus mehreren Tabellen in der Datenbank. Hier sind die Schritte dazu.
Suchen Sie die Datenbankanmeldeinformationen.
Auf einem Linux-System, auf dem das MythTV-Frontend ausgeführt wird, gibt es eine Datei ~/.mythtv/config.xml .
<CONFIGURATION>
<LOCALHOSTNAME>my-unique-identifier-goes-here</LOCALHOSTNAME>
<DATABASE>
<PINGHOST>1</PINGHOST>
<HOST>closet.local</HOST>
<USERNAME>mythtv</USERNAME>
<PASSWORD>this is the pw</PASSWORD>
<DATABASENAME>mythconverg</DATABASENAME>
<PORT>3306</PORT>
</DATABASE>
<WAKEONLAN>
<ENABLED>0</ENABLED>
<SQLRECONNECTWAITTIME>0</SQLRECONNECTWAITTIME>
<SQLCONNECTRETRY>5</SQLCONNECTRETRY>
<COMMAND>echo 'WOLsqlServerCommand not set'</COMMAND>
</WAKEONLAN>
<UPNP>
<UDN>
<MEDIARENDERER>52d20477-fda1-4e42-9edd-5992bd0ca45f</MEDIARENDERER>
</UDN>
</UPNP>
</CONFIGURATION>
Kopieren Sie die Datei an einen Ort, an dem Ihre Kopie von JMP sie lesen kann, und öffnen Sie sie mit JMP 15 wie folgt:
// grab user name and password from the XML config file
dtConfig = Open( "F:\mythconfig.xml", invisible, XML Wizard( 0, guess( "huge" ) ) );
was eine versteckte Tabelle wie diese erstellt
JMP data table loaded from XML file with one row and columns for UserName, Password, and DatabaseNameJMP data table loaded from XML file with one row and columns for UserName, Password, and DatabaseNameJMP data table loaded from XML file with one row and columns for UserName, Password, and DatabaseNameJMP data table loaded from XML file with one row and columns for UserName, Password, and DatabaseNameAus XML-Datei geladene JMP-Datentabelle mit einer Zeile und Spalten für Benutzername, Kennwort und Datenbankname
Closet.local ist der Name des Backend-Hosts, mythtv ist der SQL-Benutzername, der Zugriff auf die mythconverg-Datenbank hat, und 3306 ist der Standardport, sodass er nicht benötigt wird.
Erstellen Sie einen DSN mit dem Windows ODBC Data Source Administrator.
Sie benötigen wahrscheinlich die 64-Bit-Treiber und müssen sie möglicherweise herunterladen. https://dev.mysql.com/downloads/connector/odbc/ oder vielleicht https://downloads.mariadb.org/connector-odbc/+releases/ . Ich bin mir ziemlich sicher, dass ich MariaDB tatsächlich auf meinem Backend-Server ausführe und den MySQL-Connector am Frontend verwende. https://www.google.com/search?q=mysql+vs+mariadb
The Windows ODBC Data Source Administrator sets up a DSNThe Windows ODBC Data Source Administrator sets up a DSNThe Windows ODBC Data Source Administrator sets up a DSNThe Windows ODBC Data Source Administrator sets up a DSNDer Windows ODBC-Datenquellenadministrator richtet einen DSN ein
Drücken Sie Konfigurieren und fügen Sie einige Felder hinzu; Ich denke, diese können später alle über eine Verbindungszeichenfolge überschrieben werden. Meine VirtualBox und mein Netzwerk und mein Server sind nicht zufrieden mit schrank.local für den Servernamen, sodass die gepunktete IP verwendet wird. Sie können den Benutzer und das Passwort eingeben und die Verbindung testen und die verfügbaren Datenbanknamen anzeigen. Die JSL unten wird diese überschreiben.
The ODBC Connector dialog supplies some information that can be overridden laterThe ODBC Connector dialog supplies some information that can be overridden laterThe ODBC Connector dialog supplies some information that can be overridden laterThe ODBC Connector dialog supplies some information that can be overridden laterDer Dialog ODBC Connector liefert einige Informationen, die später überschrieben werden können
Entdecken Sie die Tabellennamen in den MythTV-Datenbanken
Dank eines Beispiels aus @briancorcoran für den Wegweiser mit dem nächsten Stück JSL.
https://community.jmp.com/t5/Discussions/How-do-I-get-the-list-of-the-databases-available-on-a-designated/mp/10589
// DSN=Mythtv comes from the windows ODBC Data Source Administrator applet
dt = Open Database(
"DSN=Mythtv;UID=" || dtConfig:UserName[1] || ";PWD=" || dtConfig:Password[1],
"SHOW tables from " || dtConfig:DatabaseName[1] || ";",
"tables in " || dtConfig:DatabaseName[1]
);
Diese JSL verwendet die JMP-Datentabelle dtConfig, die oben aus der XML-Konfigurationsdatei geöffnet wurde, um das tatsächliche Passwort und andere Informationen zum Überschreiben des DSN (der auch mythtv heißt, unabhängig vom Benutzernamen) abzurufen. Brians Beispiel verwendete SHOW DATABASES. Diese JSL verwendet SHOW TABLES FROM mythconverg, um die über 80 Tabellen aus der mythtv-Datenbank namens mythconverg abzurufen.
(SQL kann mehrere Datenbanken haben, und eine Datenbank kann mehrere Tabellen haben. Datenbanken interagieren nicht miteinander, aber Tabellen innerhalb einer Datenbank haben oft gemeinsame Schlüssel, die es ermöglichen, zwei Tabellen zu verbinden. Also eine Datenbank für Haustiere, eine Datenbank für Rezepte und eine Datenbank für MythTV. Innerhalb der MythTV-Datenbank Tabellen, die beschreiben, welche Programme aufgezeichnet werden sollen, und Tabellen, die beschreiben, welche Programme aufgezeichnet wurden, und viele andere Tabellen ...)
A JMP data table from Open Database(...) showing the 88 table names in the databaseA JMP data table from Open Database(...) showing the 88 table names in the databaseA JMP data table from Open Database(...) showing the 88 table names in the databaseA JMP data table from Open Database(...) showing the 88 table names in the databaseEine JMP-Datentabelle von Open Database(...) mit den 88 Tabellennamen in der Datenbank
Fangen Sie an, die Form der Datenbank zu rätseln
Wenn Sie dies falsch machen UND in die Datenbank schreiben, werden Sie die Datenbank beschädigen. Du könntest die lesen gehen Quellcode für MythTV und vielleicht finden Sie sogar ein Dokument, das erklärt, wie die Tabellen funktionieren, oder Sie können die spannende Frage stellen: Kann ich morgen noch aufgezeichnetes Fernsehen sehen? Was folgt, ist der spannende Weg.
Sehen Sie sich die Tabellennamen der Datenbank in der Datentabelle oben an und prüfen Sie, ob es interessante gibt. Es gibt, aber es ist noch nicht klar, was sie darstellen.
two of the high lighted table names, record and recorded, look promisingtwo of the high lighted table names, record and recorded, look promisingtwo of the high lighted table names, record and recorded, look promisingtwo of the high lighted table names, record and recorded, look promisingzwei der hervorgehobenen tabellennamen, record undrecorded, sehen vielversprechend aus
Hier ist eine einfache Möglichkeit, einen Blick auf die Tabellen und ihre Spalten und einen Teil ihrer Daten zu werfen.
Datei→Datenbank→OpenTable
The OpenTable dialog opens one database table into a JMP data tableThe OpenTable dialog opens one database table into a JMP data tableThe OpenTable dialog opens one database table into a JMP data tableThe OpenTable dialog opens one database table into a JMP data tableDer OpenTable-Dialog öffnet eine Datenbanktabelle in einer JMP-Datentabelle
Es gibt 50 Spalten in dieser Tabelle, aber diejenige, die hervorsticht, ist die Beschreibung:
The record table seems to describe what to recordThe record table seems to describe what to recordThe record table seems to describe what to recordThe record table seems to describe what to recordDie Aufzeichnungstabelle scheint zu beschreiben, was aufgezeichnet werden soll
Das ist eine Beschreibung dessen, was aufgezeichnet werden soll (oder was vielleicht nicht aufgezeichnet werden soll … Ich habe diese Regel geschrieben.) Dies ist nicht die Tabelle, die ich brauche.
Was ist mit der Tabelle namens recorded?
The recorded table seems to be a list of programs that were recordedThe recorded table seems to be a list of programs that were recordedThe recorded table seems to be a list of programs that were recordedThe recorded table seems to be a list of programs that were recordedDie aufgezeichnete Tabelle scheint eine Liste von Programmen zu sein, die aufgezeichnet wurden
Das sieht aus wie eine Tabelle aufgezeichneter Sendungen. Dies wird ein Ausgangspunkt sein.
Verbinden Sie einige Tische, um alles, was Sie brauchen, an einem Ort zu bekommen
File→Database→Query Builder, wählen Sie die aufgezeichnete Tabelle…
Query Builder starts by choosing a single tableQuery Builder starts by choosing a single tableQuery Builder starts by choosing a single tableQuery Builder starts by choosing a single tableDer Abfrage-Generator beginnt mit der Auswahl einer einzelnen Tabelle
Wenn Sie WEITER drücken, erhalten Sie dieses Erstaunliche @Eric_Hill Zwischenfenster:
The amazing Select Tables windows can view other tables and join them to the first tableThe amazing Select Tables windows can view other tables and join them to the first tableThe amazing Select Tables windows can view other tables and join them to the first tableThe amazing Select Tables windows can view other tables and join them to the first tableDie erstaunlichen Fenster "Tische auswählen" können andere Tische anzeigen und sie mit dem ersten Tisch verbinden
Dieses Fenster dient zum Durchsuchen von Tabellen. Klicken Sie noch nicht auf Abfrage erstellen, das führt Sie zu einem Fenster, in dem Sie Spalten auswählen. Verwenden Sie vorher dieses Fenster, um anderen Tischen beizutreten.
(Sie können später zu diesem Fenster zurückkehren, aber Sie sollten in der Lage sein, alles zu finden, was Sie später bei Ihrem ersten Besuch benötigen ... vielleicht.)
Clicking a table shows a snapshotClicking a table shows a snapshotClicking a table shows a snapshotClicking a table shows a snapshotDurch Klicken auf eine Tabelle wird ein Schnappschuss angezeigt
Folgendes habe ich am Ende verwendet (fast, siehe unten für eine weitere Änderung):
Three more tables joined with the firstThree more tables joined with the firstThree more tables joined with the firstThree more tables joined with the firstDrei weitere Tische schlossen sich dem ersten an
Ich habe die (oben ausgewählte) aufgezeichnete Datei verwendet, um die Dateigröße zu erhalten, an die sich die Datenbank erinnert. Ich denke, diese Datenbank ist nicht normalisiert, da der Basisname in der aufgezeichneten und aufgezeichneten Datei erscheint ... https://en.wikipedia.org/wiki/Database_normalization
(Die Schaltflächen unten sind anders, weil ich die rote Dreiecksschaltfläche "Gehe zurück, um weitere Tabellen auszuwählen" in Build Query verwendet habe, um dieses Bild zu erhalten ... Wenn Sie auf OK drücken, kehren Sie zum Fenster Build Query zurück.)
Hier steckt viel Leistung: Sie können den Join mit der Schaltfläche mit dem blauen Kreis steuern, Sie können einen Schnappschuss jeder Tabelle in der Spalte sehen und das Ergebnis des Joins in der Vorschau anzeigen. Und alle Tische sind aufgelistet! Hier wird das Rätsel gelöst: Welche Tische werden benötigt und wie werden sie zusammengehängt? Wählen Sie die Registerkarte Tabellen-Snapshot, wählen Sie eine Tabelle in der linken Spalte aus und verwenden Sie den Abwärtspfeil, um jede Tabelle anzuzeigen. Viele der MythTV-Tabellen sind leer, was bedeutet, dass ich sie ignorieren kann.
Wählen Sie die Spalten aus, die beibehalten werden sollen
Es ist an der Zeit, auf die Schaltfläche „Abfrage erstellen“ zu klicken. In diesem Fenster können Sie die gewünschten Spalten auswählen und die Abfrage ausprobieren:
Build Query window chooses columns to keep in the JMP data tableBuild Query window chooses columns to keep in the JMP data tableBuild Query window chooses columns to keep in the JMP data tableBuild Query window chooses columns to keep in the JMP data tableDas Fenster „Abfrage erstellen“ wählt Spalten aus, die in der JMP-Datentabelle beibehalten werden sollen
Diese Doppel-X-Schaltfläche löscht alle Spaltenauswahlen; Wahrscheinlich möchten Sie auf das einzelne X klicken, um nur die ausgewählte Spalte zu löschen. Verschieben Sie die Zeilen, die die Spalten beschreiben, nach oben und unten, um die Spalten zu ordnen, und wählen Sie eine Spalte aus, um die Daten vorzusortieren.
Wählen Sie „Abfrage ausführen“, studieren Sie die Tabelle, überdenken Sie …
Aus dem obigen Dialog bringt Sie das rote Dreieck neben Tabellen zurück zum Dialog zum Hinzufügen einer weiteren Tabelle (der erstaunliche). Ich brauchte einen anderen Tisch, um wirklich zu verstehen, was los war.
Added another table, recgroupAdded another table, recgroupAdded another table, recgroupAdded another table, recgroupEine weitere Tabelle hinzugefügt, recgroup
Die Tabelle recgroups hat das Kennzeichen Gelöschte Gruppe. Hier ist ein Teil des Ergebnisses (ähnlich der ursprünglichen Tabelle oben). Alle diese Basisnamen befinden sich in der Standardgruppe, nicht in der gelöschten Gruppe.
The filesize column suggests there is a lot of space I might recoverThe filesize column suggests there is a lot of space I might recoverThe filesize column suggests there is a lot of space I might recoverThe filesize column suggests there is a lot of space I might recoverDie Dateigröße-Spalte deutet darauf hin, dass viel Speicherplatz vorhanden ist, den ich möglicherweise wiederherstellen könnte
So viel Platz verloren!
Hier ist das JSL/SQL aus dem Quellskript in der Tabelle. Ändern Sie <<<Ändern, um im Builder-Dialog für weitere Bearbeitungen zu öffnen!
New SQL Query(
Connection( "ODBC:DSN=mythtv;SERVER=192.168.0.39;UID=mythtv;DATABASE=mythconverg;PORT=3306;PWD=%_PWD_%;"
),
QueryName( "recorded" ),
Select(
Column( "callsign", "t3" ),
Column( "channum", "t3" ),
Column( "starttime", "t1", Numeric Format( "m/d/y h:m:s", "0", "NO", "" ) ),
Column( "endtime", "t1", Numeric Format( "m/d/y h:m:s", "0", "NO", "" ) ),
Column( "title", "t1" ),
Column( "description", "t1" ),
Column( "autoexpire", "t1" ),
Column( "preserve", "t1" ),
Column( "deletepending", "t1" ),
Column( "recgroup", "t4" ),
Column( "basename", "t2" ),
Column( "filesize", "t2" ),
Column( "width", "t2" ),
Column( "height", "t2" ),
Column( "fps", "t2" ),
Column( "videoprop", "t5" ),
Column( "subtitletypes", "t5" )
),
From(
Table( "recorded", Alias( "t1" ) ),
Table( "recgroups", Alias( "t4" ),
Join( Type( Left Outer ),
EQ( Column( "recgroupid", "t1" ), Column( "recgroupid", "t4" ) )
)
),
Table( "recordedprogram", Alias( "t5" ),
Join(
Type( Left Outer ),
EQ( Column( "chanid", "t1" ), Column( "chanid", "t5" ) ) &
EQ(
Column("starttime","t1",Numeric Format( "m/d/y h:m:s", "0", "NO", "" ) ),
Column("starttime","t5",Numeric Format( "m/d/y h:m:s", "0", "NO", "" ) )
)
)
),
Table( "recordedfile", Alias( "t2" ),
Join( Type( Left Outer ),
EQ( Column( "recordedid", "t1" ), Column( "recordedid", "t2" ) )
)
),
Table( "channel", Alias( "t3" ),
Join( Type( Left Outer ),
EQ( Column( "chanid", "t1" ), Column( "chanid", "t3" ) )
)
)
),
Order By( Column( "starttime", "t1", Numeric Format( "m/d/y h:m:s", "0", "NO", "" ),
Order( "Ascending" ) )
)
) << Run;
Also muss ich einen kleinen Test machen: Berühren Sie für eine einzelne hängengebliebene Datei die Datenbank, um Autoexpire wieder einzuschalten und Deletepending auszuschalten. Und vielleicht das Backend stoppen und neu starten. Beobachten Sie dann, ob die Datei irgendwann in den nächsten Stunden oder Tagen gelöscht wird ... dieser Teil des Verhaltens von MythTV, Just-in-Time-Löschen, ist ebenfalls verwirrend.
H mmm. Gehen Sie lieber langsam. Die Gesamtdateigröße in der Datenbank Ist doppelt so groß wie die Scheibe.Löschen wir diese hier: 1171_20180321043700.ts
Machen Sie zuerst eine Abfrage, um es zu finden, mit einem Filter. Ich gehe diesen Weg, weil JMP die meiste Arbeit in einer GUI für mich erledigen kann und ich mich nicht ganz wohl fühle, SQL ohne Hilfe zu schreiben. Ich werde die SQL ändern, nachdem JMP den schwierigen Teil für mich erledigt hat.
Add a filter to select a single basename (file)Add a filter to select a single basename (file)Add a filter to select a single basename (file)Add a filter to select a single basename (file)Fügen Sie einen Filter hinzu, um einen einzelnen Basisnamen (Datei) auszuwählen
Hübsch! Der Filter fügte der SQL die WHERE-Klausel hinzu und es wurde genau eine Zeile gefunden. Ich denke, es ist Zeit, das SQL aus dem zu kopieren Abfrage Ersteller Dialog; müssen den mythconverg hinzufügen. vor jedem Tabellennamen :
// grab user name and password from the XML config file
dtConfig = Open( "F:\mythconfig.xml", invisible, XML Wizard( 0, guess( "huge" ) ) );
//https://community.jmp.com/t5/Discussions/How-do-I-get-the-list-of-the-databases-available-on-a-designated/m-p/10589
// dtConfig:UserName,Password,DatabaseName
//
// DSN=Mythtv comes from the windows ODBC Data Source Administrator applet
dbc=CreateDatabaseConnection("DSN=Mythtv;UID=" || dtConfig:UserName[1] || ";PWD=" || dtConfig:Password[1]);
rc=executesql(dbc,"\[
SELECT t3.callsign, t3.channum, t1.starttime, t1.endtime,
t1.title, t1.description, t1.autoexpire, t1.preserve,
t1.deletepending, t4.recgroup, t2.basename, t2.filesize,
t2.width, t2.height, t2.fps, t5.videoprop,
t5.subtitletypes
FROM mythconverg.recorded t1
LEFT OUTER JOIN mythconverg.recgroups t4
ON ( t1.recgroupid = t4.recgroupid )
LEFT OUTER JOIN mythconverg.recordedprogram t5
ON ( ( t1.chanid = t5.chanid ) AND ( t1.starttime = t5.starttime ) )
LEFT OUTER JOIN mythconverg.recordedfile t2
ON ( t1.recordedid = t2.recordedid )
LEFT OUTER JOIN mythconverg.channel t3
ON ( t1.chanid = t3.chanid )
WHERE ( ( ( t2.basename="1171_20180321043700.ts" ) ) )
ORDER BY t1.starttime ASC;
]\","one row");
Close Database Connection(dbc);
close(dtConfig,nosave);
show(nrows(rc)==1); // better only be one row
WARNUNG, GEFÄHRLICHER CODE FOLGT, SIE KÖNNTEN IHRE DATENBANK MIT UPDATE UND SET LÖSCHEN.
und ersetzen Sie SELECT ... AUS mit UPDATE und eine SET-Klausel hinzufügen und ORDER BY entfernen:
// grab user name and password from the XML config file
dtConfig = Open( "F:\mythconfig.xml", invisible, XML Wizard( 0, guess( "huge" ) ) );
dbc=CreateDatabaseConnection("DSN=Mythtv;UID=" || dtConfig:UserName[1] || ";PWD=" || dtConfig:Password[1]);
rc=executesql(dbc,"\[
UPDATE mythconverg.recorded t1
LEFT OUTER JOIN mythconverg.recgroups t4
ON ( t1.recgroupid = t4.recgroupid )
LEFT OUTER JOIN mythconverg.recordedprogram t5
ON ( ( t1.chanid = t5.chanid ) AND ( t1.starttime = t5.starttime ) )
LEFT OUTER JOIN mythconverg.recordedfile t2
ON ( t1.recordedid = t2.recordedid )
LEFT OUTER JOIN mythconverg.channel t3
ON ( t1.chanid = t3.chanid )
SET t1.autoexpire=1, t1.deletepending=0
WHERE ( ( ( t2.basename="1171_20180321043700.ts" ) ) );
]\","update");
Close Database Connection(dbc);
close(dtConfig,nosave);
Das erneute Abrufen der Tabelle zeigt das Update:
The UPDATE and SET workedThe UPDATE and SET workedThe UPDATE and SET workedThe UPDATE and SET workedDas UPDATE und SET funktionierte
Ich bin mir nicht sicher, wie ich den Status des Updates erhalte; der rc war ein fehlender Wert und es wurde keine Tabelle erstellt, was Sinn macht. Aber es hat funktioniert…
Einige Minuten später ist die Datei immer noch vorhanden. Ich werde das Backend neu starten. Neu gestartet. Die Datei wird jetzt im Frontend angezeigt.
Part of the frontend GUI shows the ancient file is visible againPart of the frontend GUI shows the ancient file is visible againPart of the frontend GUI shows the ancient file is visible againPart of the frontend GUI shows the ancient file is visible againEin Teil der Frontend-GUI zeigt, dass die alte Datei wieder sichtbar ist
Ich werde mich zurücklehnen und sehen, ob es in ein paar Tagen auf der Festplatte verschwindet. Dann werde ich an den restlichen solchen arbeiten und sehen, warum die Datenbank zu glauben scheint, dass sich 6T auf einer 3T-Festplatte befinden ...
Ein paar Stunden später: ls: Zugriff auf „1171_20180321043700.ts“ nicht möglich: Keine solche Datei oder kein solches Verzeichnis
Wie oben erwähnt (normalisierter Kommentar), erscheint der Dateiname in mehr als einer Tabelle. Mein Plan, das 6T auf ein realistischeres 3T zu bereinigen, geht davon aus, dass es Einträge in der aufgezeichneten Tabelle gibt, die auf Dateien verweisen, die sich nicht mehr auf der Festplatte befinden. Anstatt zu versuchen, Datensätze aus beiden (und vielleicht mehr?) Tabellen zu löschen, denke ich, dass ich eine Dummy-Datei erstellen werde, wenn es keine gibt, und den vorhandenen Code auf die übliche Weise damit umgehen lasse. Vielleicht wäre es ein guter erster Schritt, einfach sowohl die Datenbanktabellen der aufgezeichneten als auch der aufgezeichneten Dateien in JMP-Datentabellen zu öffnen und festzustellen, wo Dateien auf der Festplatte fehlen und zwischen den Tabellen inkonsistent sind.
Datei→Datenbank→OpenTable wird es tun. Löschen Sie alle Spalten außer Basisname und aufgezeichnete ID, sortieren Sie nach aufgezeichneter ID, vergleichen Sie Datentabellen. Drei Diffs zum Anklicken. Einfach.
Neugierig: 1171_20180317233200.ts ist in aufgezeichneter, aber nicht aufgezeichneter Datei
und liegt als 0-Byte-Datei vor -rw-rw-r-- 1 mythtv mythtv 0 Apr 4 2018 1171_20180317233200.ts
Und es gibt zwei Einträge mit einem völlig leeren Namen in der aufgezeichneten Datei, die keine übereinstimmende aufgezeichnete ID in aufgezeichnet haben. Ich möchte diese wahrscheinlich nicht bereinigen, ohne zu sagen, auf welche anderen Tabellen sie sich beziehen könnten.
Die oben gelöschte Datei, 1171_20180321043700.ts , taucht in keiner der Tabellen auf. Yay!
Ich werde aufgezeichnet als Wahrheit verwenden, da es keine leeren Aufzeichnungen gibt. Ich verwende eine Spaltenformel mit der Funktion fileexists(), um zu sehen, was vor sich geht.
Graph; points at top represent real files on disk, points at bottom are files that are not on diskGraph; points at top represent real files on disk, points at bottom are files that are not on diskGraph; points at top represent real files on disk, points at bottom are files that are not on diskGraph; points at top represent real files on disk, points at bottom are files that are not on diskGraph; Punkte oben stellen echte Dateien auf der Festplatte dar, Punkte unten sind Dateien, die sich nicht auf der Festplatte befinden
Es besteht die Möglichkeit, dass ich viel Speicherplatz zurückbekomme, aber in diesem Cluster, den ich löschen möchte, befinden sich möglicherweise viele Dateien mit der Länge null oder nahezu null. Zeit für eine Pause, sollte nicht um 21 Uhr beginnen.
Um die Frage „wie viel?“ zu beantworten Frage, verwenden Sie filesize() anstelle von fileexists(). Viele der Dateien existieren, sind aber null Bytes, sodass nur etwa 0,3 TB (10 % !) wiederherstellbarer Speicherplatz vorhanden sind.
Phase 1: Dummy-Dateien für die nicht existierenden Dateien hinzufügen, damit MythTV sie später bereinigen kann. Der Grund, warum die Datensätze in der Datenbank bleiben, wenn MythTV die Dateien nicht finden kann, ist, dass MythTV davon ausgeht, dass sich die Dateien möglicherweise auf einer nicht verfügbaren Festplatte befinden und verwaisen würden, wenn der Datenbankeintrag entfernt würde.
// actualsize is this formula:
// File Size( "f:/closet/" || :basename )
For Each Row(
If( :basename != "" & Is Missing( actualsize ),
If( !File Exists( "f:/closet/" || :basename ),
Show( :basename );
Save Text File( "f:/closet/" || :basename, "hi there" );// use “touch” on Linux
, // else
Throw( "oops" )
)
)
);
Write( "\!ndone" );
Phase 2: Holen Sie eine neue Kopie der Datenbank in eine Datentabelle. Es sieht gut aus. Zeit, die SQL zu überarbeiten, um zu sehen, ob wir nur die zu aktualisierenden Datensätze auswählen können:
// grab user name and password from the XML config file
dtConfig = Open( "F:\mythconfig.xml", invisible, XML Wizard( 0, guess( "huge" ) ) );
dbc=CreateDatabaseConnection("DSN=Mythtv;UID=" || dtConfig:UserName[1] || ";PWD=" || dtConfig:Password[1]);
rc=executesql(dbc,"\[
SELECT t3.callsign, t3.channum, t1.starttime, t1.endtime,
t1.title, t1.description, t1.autoexpire, t1.preserve,
t1.deletepending, t4.recgroup, t2.basename, t2.filesize,
t2.width, t2.height, t2.fps, t5.videoprop,
t5.subtitletypes
FROM mythconverg.recorded t1
LEFT OUTER JOIN mythconverg.recgroups t4
ON ( t1.recgroupid = t4.recgroupid )
LEFT OUTER JOIN mythconverg.recordedprogram t5
ON ( ( t1.chanid = t5.chanid ) AND ( t1.starttime = t5.starttime ) )
LEFT OUTER JOIN mythconverg.recordedfile t2
ON ( t1.recordedid = t2.recordedid )
LEFT OUTER JOIN mythconverg.channel t3
ON ( t1.chanid = t3.chanid )
WHERE ( ( ( t1.deletepending=1 ) ) )
ORDER BY t1.starttime ASC;
]\","one row");
Close Database Connection(dbc);
close(dtConfig,nosave);
show(nrows(rc)==1);
Das wählt ungefähr die Hälfte der Aufzeichnungen aus, alle ziemlich alt, die mit dem Löschen anhängig sind. Zeit, mutig zu werden …
Phase 3: Mach es.
WARNUNG, GEFÄHRLICHER CODE FOLGT, SIE KÖNNTEN IHRE DATENBANK MIT UPDATE UND SET LÖSCHEN.
// grab user name and password from the XML config file
dtConfig = Open( "F:\mythconfig.xml", invisible, XML Wizard( 0, guess( "huge" ) ) );
dbc=CreateDatabaseConnection("DSN=Mythtv;UID=" || dtConfig:UserName[1] || ";PWD=" || dtConfig:Password[1]);
rc=executesql(dbc,"\[
UPDATE mythconverg.recorded t1
LEFT OUTER JOIN mythconverg.recgroups t4
ON ( t1.recgroupid = t4.recgroupid )
LEFT OUTER JOIN mythconverg.recordedprogram t5
ON ( ( t1.chanid = t5.chanid ) AND ( t1.starttime = t5.starttime ) )
LEFT OUTER JOIN mythconverg.recordedfile t2
ON ( t1.recordedid = t2.recordedid )
LEFT OUTER JOIN mythconverg.channel t3
ON ( t1.chanid = t3.chanid )
SET t1.autoexpire=1, t1.deletepending=0
WHERE ( ( ( t1.deletepending=1 ) ) );
]\","update");
Close Database Connection(dbc);
close(dtConfig,nosave);
Die ausstehenden Löschungen sind nicht mehr anhängig und die automatische Verfallszeit ist wieder aktiviert. Zeit zum Abwarten.
Am nächsten Morgen: Ich glaube, es funktioniert; hätte besser Notizen machen sollen. Hier sind die ältesten Dateien, die noch herumhängen, bevor die Morgennachrichtensendungen aufgezeichnet werden (Montag um 6:50 Uhr):
-rw-r--r-- 1 mythtv mythtv 1.9G 22. März 2018 1111_20180322080000.ts
-rw-r--r-- 1 mythtv mythtv 3.2G 22. März 2018 1051_20180322080000.ts
-rw-rw-rw- 1 mythtv mythtv 1.1M 22. März 2018 1111_20180322043700.ts.png
-rw-r--r-- 1 mythtv mythtv 11G 22. März 2018 1171_20180322060700.ts
-rw-r--r-- 1 mythtv mythtv 5.6G 22. März 2018 1111_20180322063000.ts
-rw-rw-rw- 1 mythtv mythtv 1.4M 22. März 2018 1051_20180322033500.ts.png
-rw-r--r-- 1 mythtv mythtv 3.2G 22. März 2018 1051_20180322070000.ts
-rw-r--r-- 1 mythtv mythtv 5.7G 22. März 2018 1051_20180322060700.ts
-rw-r--r-- 1 mythtv mythtv 3.2G 22. März 2018 1051_20180322053700.ts
-rw-r--r-- 1 mythtv mythtv 1.6G 22. März 2018 1111_20180322053700.ts
-rw-r--r-- 1 mythtv mythtv 6.4G 22. März 2018 1051_20180322043700.ts
-rw-r--r-- 1 mythtv mythtv 5.4G 22. März 2018 1171_20180322043700.ts
-rw-rw-rw- 1 mythtv mythtv 1.4M 22. März 2018 1171_20180322030000.ts.png
-rw-rw-rw- 1 mythtv mythtv 3.4M 22. März 2018 1051_20180322030100.ts.png
-rw-r--r-- 1 mythtv mythtv 2.1G 22. März 2018 1111_20180322043700.ts
-rw-rw-rw- 1 mythtv mythtv 511K 22. März 2018 1111_20180322030000.ts.png
-rw-r--r-- 1 mythtv mythtv 6.6G 22. März 2018 1051_20180322033500.ts
-rw-r--r-- 1 mythtv mythtv 3.8G 22. März 2018 1111_20180322033500.ts
-rw-r--r-- 1 mythtv mythtv 3.3G 21. März 2018 1171_20180322030000.ts
-rw-r--r-- 1 mythtv mythtv 3.7G 21. März 2018 1051_20180322030100.ts
-rw-r--r-- 1 mythtv mythtv 2.4G 21. März 2018 1111_20180322030000.ts
-rw-r--r-- 1 mythtv mythtv 3.3G 21. März 2018 1051_20180321233000.ts
-rw-rw-rw- 1 mythtv mythtv 725K 21. März 2018 1111_20180321200000.ts.png
-rw-rw-rw- 1 mythtv mythtv 2.6M 21. März 2018 1051_20180321200000.ts.png
-rw-r--r-- 1 mythtv mythtv 2.9G 21. März 2018 1051_20180321200000.ts
-rw-r--r-- 1 mythtv mythtv 1.8G 21. März 2018 1111_20180321200000.ts
-rw-rw-rw- 1 mythtv mythtv 897K 21. März 2018 1111_20180321163000.ts.png
-rw-r--r-- 1 mythtv mythtv 3.2G 21. März 2018 1051_20180321163000.ts
-rw-r--r-- 1 mythtv mythtv 2.0G 21. März 2018 1111_20180321163000.ts
-rw-r--r-- 1 mythtv mythtv 2.0G 21. März 2018 1111_20180321160000.ts
-rw-r--r-- 1 mythtv mythtv 102M 21. März 2018 1171_20180321160000.ts
-rw-r--r-- 1 mythtv mythtv 26G 21. März 2018 1051_20180321110000.ts
-rw-r--r-- 1 mythtv mythtv 8.1G 21. März 2018 1111_20180321110000.ts
-rw-r--r-- 1 mythtv mythtv 3.3G 21. März 2018 1171_20180321100000.ts
-rw-r--r-- 1 mythtv mythtv 6.2G 21. März 2018 1051_20180321100000.ts
-rw-r--r-- 1 mythtv mythtv 3.9G 21. März 2018 1111_20180321100000.ts
-rw-rw-rw- 1 mythtv mythtv 743K 20. März 2018 1281_20180321010000.ts.png
-rw-rw-rw- 1 mythtv mythtv 867K 20. März 2018 1281_20180321002000.ts.png
drwxr-xr-x 12 root root 4.0K 20. März 2018 ..
drwx------ 2 root root 16K 28. Feb. 2018 lost+found
Programs recorded Friday will be recorded again today (Monday)Programs recorded Friday will be recorded again today (Monday)Programs recorded Friday will be recorded again today (Monday)Programs recorded Friday will be recorded again today (Monday)Sendungen, die am Freitag aufgezeichnet wurden, werden heute (Montag) erneut aufgezeichnet.
Diese drei Programme verbrauchten letzten Freitag etwa 40 GB. Um 9:30 Uhr wurden die letzten 13,4 G in der aufgezeichneten Tabelle gelöscht. Ich bin mir nicht sicher, woher die anderen 15G kamen. Vielleicht hatte die Löschwarteschlange bereits einige Dateien. Vielleicht wurden diese in der Reihenfolge der ältesten zuerst hinzugefügt, nach einigen anderen ... Ich versuche, tagsüber kein Fernsehen aufzuzeichnen, also kann es heute Abend dauern, bis ich sehe, dass weitere Dateien gelöscht werden. (Ja, es passiert!) Ich hoffe, die (riesigen) PNG-Miniaturansichten kümmern sich auch um sich selbst, zu früh, um das zu sagen.
Was ich über JMP und SQL gelernt habe: Es gibt eine wirklich einfache Möglichkeit, eine SQL-Tabelle in eine JMP-Datentabelle zu laden, wenn keine Verknüpfung erforderlich ist (Datei → Datenbank → Tabelle öffnen). Es gibt ein wirklich nettes Power-Tool zum Lesen von Tabellen, das muss verknüpft werden (Datei→Datenbank→Abfragegenerator). Beide generieren auch ein JSL-Skript in der Tabelle, das wiederverwendet werden kann. Und wenn Sie die Datenbank aktualisieren müssen, müssen Sie die Funktion ExecueSQL() verwenden, aber Sie können den Query Builder dazu bringen, das SQL zu erstellen, das fast das ist, was Sie brauchen, und es dann ändern, indem Sie ein UPDATE/SET ausführen.
Ich habe in der Vergangenheit einen Teil der SQL-Arbeit außerhalb von JMP erledigt. Ich fand es wirklich nett, JSL zu verwenden, um einige Nicht-SQL-Arbeiten zu erledigen (Erstellen von Dummy-Dateien, Erstellen von Diagrammen der Festplattennutzung), die mir geholfen haben, die Datenbank besser zu verstehen.
https://code.mythtv.org/cgit/mythtv/tree/mythtv/programs/mythbackend/autoexpire.cpp Ausgangspunkt für den MythTV-Quellcode zum Bereinigen alter Dateien
https://en.wikipedia.org/wiki/Cord-cutting
Scheint alles wieder normal zu sein. Diese letzte Grafik zeigt, wie verschiedene Stationen ihre verfügbare Bandbreite optimiert haben. Die Bandbreite kann in einen oder mehrere Kanäle aufgeteilt werden; Mehr Kanäle reduziert bedeutet weniger Daten, um ein qualitativ hochwertiges Bild zu erstellen. Einer der lokalen Sender entschied sich auch für 720 60 FPS statt 1080 30 FPS, was bedeutet, dass es vielleicht kein Vergleich von Äpfeln zu Äpfeln ist. Jeder der hervorgehobenen Kanäle hat wahrscheinlich einen oder mehrere andere Kanäle von derselben Station, mit der er Bandbreite teilt. Auf den grauen Sendern unten laufen möglicherweise mehrere alte Filme gleichzeitig oder Einkaufskanäle. Sie wurden aus der Legende entfernt.
Lines with bigger slope have more bandwidth allocated to the pictureLines with bigger slope have more bandwidth allocated to the pictureLines with bigger slope have more bandwidth allocated to the pictureLines with bigger slope have more bandwidth allocated to the pictureLinien mit größerer Steigung wird dem Bild mehr Bandbreite zugewiesen