def pt_visual_explain(queryset, display=True): if not have_program("pt-visual-explain"): # pragma: no cover raise OSError("pt-visual-explain doesn't appear to be installed") connection = connections[queryset.db] capturer = CaptureQueriesContext(connection) with capturer, connection.cursor() as cursor: sql, params = queryset.query.sql_with_params() cursor.execute("EXPLAIN " + sql, params) queries = [q["sql"] for q in capturer.captured_queries] # Take the last - django may have just opened up a connection in which # case it would have run initialization command[s] explain_query = queries[-1] # Now do the explain and pass through pt-visual-explain mysql_command = settings_to_cmd_args(connection.settings_dict) + [ "-e", explain_query, ] mysql = subprocess.Popen(mysql_command, stdout=subprocess.PIPE) visual_explain = subprocess.Popen(["pt-visual-explain", "-"], stdin=mysql.stdout, stdout=subprocess.PIPE) mysql.stdout.close() explanation = visual_explain.communicate()[0].decode(encoding="utf-8") if display: print(explanation) else: return explanation
def pt_visual_explain(queryset, display=True): if not have_program('pt-visual-explain'): # pragma: no cover raise OSError("pt-visual-explain doesn't appear to be installed") connection = connections[queryset.db] capturer = CaptureQueriesContext(connection) with capturer, connection.cursor() as cursor: sql, params = queryset.query.sql_with_params() cursor.execute('EXPLAIN ' + sql, params) queries = [q['sql'] for q in capturer.captured_queries] # Take the last - django may have just opened up a connection in which # case it would have run initialization command[s] explain_query = queries[-1] # Now do the explain and pass through pt-visual-explain mysql_command = ( settings_to_cmd_args(connection.settings_dict) + ['-e', explain_query] ) mysql = Popen(mysql_command, stdout=PIPE) visual_explain = Popen( ['pt-visual-explain', '-'], stdin=mysql.stdout, stdout=PIPE ) mysql.stdout.close() explanation = visual_explain.communicate()[0].decode(encoding="utf-8") if display: print(explanation) else: return explanation
VanillaAuthor.objects.create(name="pants") VanillaAuthor.objects.create(name="Beta") VanillaAuthor.objects.create(name="pants") bad_authors = VanillaAuthor.objects.filter(name="pants") assert bad_authors.count() == 2 with captured_stdout(): for author in SmartIterator(bad_authors, report_progress=True): author.delete() assert bad_authors.count() == 0 @skipUnless(have_program('pt-visual-explain'), "pt-visual-explain must be installed") class VisualExplainTests(TestCase): def test_basic(self): with captured_stdout() as capture: Author.objects.all().pt_visual_explain() output = capture.getvalue() # Can't be too strict about the output since different database and pt- # visual-explain versions give different output assert "testapp_author" in output assert "rows" in output assert "Table" in output def test_basic_no_display(self): output = Author.objects.all().pt_visual_explain(display=False) assert "testapp_author" in output
VanillaAuthor.objects.create(name="pants") VanillaAuthor.objects.create(name="Beta") VanillaAuthor.objects.create(name="pants") bad_authors = VanillaAuthor.objects.filter(name="pants") self.assertEqual(bad_authors.count(), 2) with captured_stdout(): for author in SmartIterator(bad_authors, report_progress=True): author.delete() self.assertEqual(bad_authors.count(), 0) @skipUnless(have_program('pt-visual-explain'), "pt-visual-explain must be installed") class VisualExplainTests(TransactionTestCase): def test_basic(self): with captured_stdout() as capture: Author.objects.all().pt_visual_explain() output = capture.getvalue() self.assertGreater(output, "") # Can't be too strict about the output since different database and pt- # visual-explain versions give different output self.assertIn("django_mysql_tests_author", output) self.assertIn("rows", output) self.assertIn("Table", output) def test_basic_no_display(self):
VanillaAuthor.objects.create(name="pants") VanillaAuthor.objects.create(name="Beta") VanillaAuthor.objects.create(name="pants") bad_authors = VanillaAuthor.objects.filter(name="pants") assert bad_authors.count() == 2 with captured_stdout(): for author in SmartIterator(bad_authors, report_progress=True): author.delete() assert bad_authors.count() == 0 @skipUnless(have_program("pt-visual-explain"), "pt-visual-explain must be installed") class VisualExplainTests(TestCase): def test_basic(self): with captured_stdout() as capture: Author.objects.all().pt_visual_explain() output = capture.getvalue() # Can't be too strict about the output since different database and pt- # visual-explain versions give different output assert "testapp_author" in output assert "rows" in output assert "Table" in output def test_basic_no_display(self): output = Author.objects.all().pt_visual_explain(display=False) assert "testapp_author" in output assert "rows" in output
assert format_duration(1) == '1s' assert format_duration(30) == '30s' assert format_duration(59) == '59s' def test_minutes(self): assert format_duration(60) == '1m0s' assert format_duration(61) == '1m1s' assert format_duration(120) == '2m0s' assert format_duration(3599) == '59m59s' def test_hours(self): assert format_duration(3600) == '1h0m0s' assert format_duration(3601) == '1h0m1s' @skipUnless(have_program('pt-fingerprint'), "pt-fingerprint must be installed") class PTFingerprintTests(SimpleTestCase): def test_basic(self): assert pt_fingerprint('SELECT 5') == 'select ?' assert pt_fingerprint('SELECT 5;') == 'select ?' def test_long(self): query = """ SELECT CONCAT(customer.last_name, ', ', customer.first_name) AS customer, address.phone, film.title FROM rental
assert format_duration(1) == '1s' assert format_duration(30) == '30s' assert format_duration(59) == '59s' def test_minutes(self): assert format_duration(60) == '1m0s' assert format_duration(61) == '1m1s' assert format_duration(120) == '2m0s' assert format_duration(3599) == '59m59s' def test_hours(self): assert format_duration(3600) == '1h0m0s' assert format_duration(3601) == '1h0m1s' @skipUnless(have_program('pt-fingerprint'), "pt-fingerprint must be installed") class PTFingerprintTests(SimpleTestCase): def test_basic(self): assert pt_fingerprint('SELECT 5') == 'select ?' assert pt_fingerprint('SELECT 5;') == 'select ?' def test_long(self): query = """ SELECT CONCAT(customer.last_name, ', ', customer.first_name) AS customer, address.phone, film.title FROM rental INNER JOIN customer ON rental.customer_id = customer.customer_id
VanillaAuthor.objects.create(name="pants") VanillaAuthor.objects.create(name="Beta") VanillaAuthor.objects.create(name="pants") bad_authors = VanillaAuthor.objects.filter(name="pants") assert bad_authors.count() == 2 with captured_stdout(): for author in SmartIterator(bad_authors, report_progress=True): author.delete() assert bad_authors.count() == 0 @skipUnless(have_program("pt-visual-explain"), "pt-visual-explain must be installed") class VisualExplainTests(TestCase): def test_basic(self): with captured_stdout() as capture: Author.objects.all().pt_visual_explain() output = capture.getvalue() # Can't be too strict about the output since different database and pt- # visual-explain versions give different output assert "testapp_author" in output assert "rows" in output assert "Table" in output def test_basic_no_display(self): output = Author.objects.all().pt_visual_explain(display=False) assert "testapp_author" in output