Это правильный ответ:
ALTER TABLE MEN DROP COLUMN Lname
Но ... если CONSTRAINT
существует на COLUMN
, то сначала вы должны DROP
CONSTRAINT
, тогда вы будете способный DROP
к COLUMN
. Чтобы сбросить CONSTRAINT
, запустите:
ALTER TABLE MEN DROP CONSTRAINT {constraint_name_on_column_Lname}
Вот измененная функция: как рекомендовано сообществом, не стесняйтесь вносить поправки в это вики сообщества.
static double Profile(string description, int iterations, Action func) {
//Run at highest priority to minimize fluctuations caused by other processes/threads
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
Thread.CurrentThread.Priority = ThreadPriority.Highest;
// warm up
func();
var watch = new Stopwatch();
// clean up
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
watch.Start();
for (int i = 0; i < iterations; i++) {
func();
}
watch.Stop();
Console.Write(description);
Console.WriteLine(" Time Elapsed {0} ms", watch.Elapsed.TotalMilliseconds);
return watch.Elapsed.TotalMilliseconds;
}
Убедитесь, что вы компилируете в Release с включенной оптимизацией, и запускаете тесты вне Visual Studio . Эта последняя часть важна, потому что JIT ограничивает свою оптимизацию подключенным отладчиком даже в режиме Release.
Если вы хотите исключить из уравнения взаимодействия с GC, вы можете запустить свой «разогревающий» вызов после вызова GC.Collect, а не до него. Таким образом, вы знаете, что .NET уже имеет достаточно памяти, выделенной из ОС для рабочего набора вашей функции.
Имейте в виду, что вы выполняете вызов метода без встроенного кода для каждой итерации, поэтому убедитесь, что вы сравниваете вещи, которые вы тестируете, на пустое тело. Вам также придется признать, что вы можете надежно рассчитать время только для тех вещей, которые в несколько раз длиннее, чем вызов метода.
Кроме того, в зависимости от того, какие данные вы профилируете,
Завершение не обязательно будет завершено до возврата GC.Collect
. Завершение ставится в очередь, а затем выполняется в отдельном потоке. Этот поток все еще может быть активен во время ваших тестов, что повлияет на результаты.
Если вы хотите убедиться, что финализация завершена перед запуском тестов, вы можете вызвать GC.WaitForPendingFinalizers
, который будет блокироваться до тех пор, пока очередь завершения очищена:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Я бы вообще избегал передачи делегата:
Пример кода, приводящего к использованию закрытия:
public void Test()
{
int someNumber = 1;
Profiler.Profile("Closure access", 1000000,
() => someNumber + someNumber);
}
Если вы не знаете о замыканиях, взгляните на этот метод в .NET Reflector.
I think the most difficult problem to overcome with benchmarking methods like this is accounting for edge cases and the unexpected. For example - "How do the two code snippets work under high CPU load/network usage/disk thrashing/etc." They're great for basic logic checks to see if a particular algorithm works significantly faster than another. But to properly test most code performance you'd have to create a test that measures the specific bottlenecks of that particular code.
I'd still say that testing small blocks of code often has little return on investment and can encourage using overly complex code instead of simple maintainable code. Writing clear code that other developers, or myself 6 months down the line, can understand quickly will have more performance benefits than highly optimized code.
Вы также должны выполнить "прогрев" перед фактическим измерением, чтобы исключить время, которое JIT-компилятор тратит на подгонку вашего кода.
Я бы вызвал func ()
несколько раз для разминки, а не только один.