Vraag: Beste tweakers, heel beknopt mijn vraag: hoe komt het dat een 'INSERT INTO' query relatief lang duurt zonder noemenswaardige server belasting? En hoe zou ik het kunnen versnellen?
Achtergrond:
Voor een project om een Neural Network op scam emails te trainen ben ik de scam email bodies van de website 419scam.org aan het scrapen met Python beautifulsoup4.
Geschat 1M emails in de database.
Nu heb ik een scraper zo geschreven, dat nadat een deel van het domein gescraped is, de email bodies worden weggeschreven naar de SQL database (+/- 300 rows per batch) en dan wordt de volgende pagina gescraped.
Het scrapen gaat heel vlot, maar het wegschrijven minder. De eerste 2k rows gingen in een oogwenk, daarna met nog slechts 2 tot 10 rows per seconde terwijl de server nauwelijks belast wordt. Gemiddeld 35kB/s writes en 1% processorbelasting. Ook de computer waar de python SQL client op draait zit duimen te draaien. Tijdens het scrapen zorgt python voor 10% processorbelasting dat naar <1% wegzakt tijdens het wegschrijven.
Het wegschrijven naar de database gaat via een stored procedure, zie hieronder.
Niks wijst er op dat de hardware het niet aankan, toch duurt het heel lang en is de write snelheid nog maar een fractie van de initiële write snelheid. Mijn vermoeden is dat de tabel onnodig lang locked is en dat alle processen op elkaar aan het wachten zijn. Daarom heb ik tijdens het draaien van het python script de volgende query afgevuurd:
Execution time: 14 minuten
Dan met nolock:
Execution time: 0.01 seconde
Waar zou dit toch door komen? Heeft iemand een idee?
Relevante software en hardware die ik gebruik
MS server 2012 virtual machine (6GB RAM, SSD storage, 2 virtual cores op een i5-3570)
SQL service: MSSQL12.MSSQLSERVER
SQL client: python3.5 mssql object
Relevante sql tabel opbouw:
Stored procedure om data weg te schrijven:
Wat ik verder geprobeerde heb:
- Python threaded gedraaid. Door meerdere threads te gebruiken kan ik de belasting op de SQL server continue houden
- INSERT INTO ... with(ROWLOCK) in de stored procedure, dit lijkt de write speed iets te verhogen en is wat constanter, maar geen drastische prestatie verbetering.
Achtergrond:
Voor een project om een Neural Network op scam emails te trainen ben ik de scam email bodies van de website 419scam.org aan het scrapen met Python beautifulsoup4.
Geschat 1M emails in de database.
Nu heb ik een scraper zo geschreven, dat nadat een deel van het domein gescraped is, de email bodies worden weggeschreven naar de SQL database (+/- 300 rows per batch) en dan wordt de volgende pagina gescraped.
Het scrapen gaat heel vlot, maar het wegschrijven minder. De eerste 2k rows gingen in een oogwenk, daarna met nog slechts 2 tot 10 rows per seconde terwijl de server nauwelijks belast wordt. Gemiddeld 35kB/s writes en 1% processorbelasting. Ook de computer waar de python SQL client op draait zit duimen te draaien. Tijdens het scrapen zorgt python voor 10% processorbelasting dat naar <1% wegzakt tijdens het wegschrijven.
Het wegschrijven naar de database gaat via een stored procedure, zie hieronder.
Niks wijst er op dat de hardware het niet aankan, toch duurt het heel lang en is de write snelheid nog maar een fractie van de initiële write snelheid. Mijn vermoeden is dat de tabel onnodig lang locked is en dat alle processen op elkaar aan het wachten zijn. Daarom heb ik tijdens het draaien van het python script de volgende query afgevuurd:
SQL:
1
| select max(ID) from table_name |
Execution time: 14 minuten
Dan met nolock:
SQL:
1
| select max(ID) from table_name with(NOLOCK) |
Execution time: 0.01 seconde
Waar zou dit toch door komen? Heeft iemand een idee?
Relevante software en hardware die ik gebruik
MS server 2012 virtual machine (6GB RAM, SSD storage, 2 virtual cores op een i5-3570)
SQL service: MSSQL12.MSSQLSERVER
SQL client: python3.5 mssql object
Relevante sql tabel opbouw:
SQL:
1
2
3
4
5
6
7
8
9
10
| CREATE TABLE [dbo].[scam419_raw]( [ID] [int] IDENTITY(1,1) NOT NULL, [timestamp] [datetime] NOT NULL, [from_address] [nvarchar](255) NULL, [reply_address] [nvarchar](255) NULL, [date] [datetime] NULL, [subject] [nvarchar](1500) NULL, [body] [text] NULL, [url] [nvarchar](255) NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] |
Stored procedure om data weg te schrijven:
SQL:
1
2
3
4
5
6
7
8
9
10
11
12
13
| ALTER PROCEDURE [dbo].[insert_raw_scam] @cur_time datetime, @from_address nvarchar(255), @reply_address nvarchar(255), @date datetime, @subject nvarchar(1500), @body text, @url nvarchar(255) AS BEGIN INSERT INTO scam419_raw (from_address, timestamp, reply_address, date, subject, body, url) (SELECT @from_address, @cur_time, @reply_address, @date,@subject, @body, @url); END; |
Wat ik verder geprobeerde heb:
- Python threaded gedraaid. Door meerdere threads te gebruiken kan ik de belasting op de SQL server continue houden
- INSERT INTO ... with(ROWLOCK) in de stored procedure, dit lijkt de write speed iets te verhogen en is wat constanter, maar geen drastische prestatie verbetering.